usecli 0.1.54__tar.gz → 0.1.56__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.54 → usecli-0.1.56}/PKG-INFO +1 -1
- {usecli-0.1.54 → usecli-0.1.56}/pyproject.toml +1 -1
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/__init__.py +45 -7
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/base_command.py +1 -37
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/shared/config/manager.py +110 -5
- {usecli-0.1.54 → usecli-0.1.56}/LICENSE +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/README.md +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/README.md +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/custom/README.md +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/custom/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/base/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/base/about_command.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/base/help_command.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/base/inspire_command.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/base/internal/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/core/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/core/utils.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/make/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/make/make_command.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/defaults/make/make_theme_command.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/commands/init_command.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/config/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/config/colors.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/error/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/error/handler.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/error/utils.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/exceptions/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/exceptions/base.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/exceptions/config.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/exceptions/usage.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/exceptions/validation.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/ui/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/ui/list.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/ui/title.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/ui/title.txt +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/validators/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/validators/network.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/validators/numeric.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/validators/path.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/core/validators/string.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/services/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/services/command_service.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/templates/command.py.j2 +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/templates/theme.toml.j2 +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/templates/usecli.config.toml.j2 +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/ayu_dark.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/catppuccin_frappe.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/catppuccin_latte.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/catppuccin_macchiato.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/catppuccin_mocha.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/default.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/dracula.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/gruvbox_dark.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/nord.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/themes/tokyo_night.toml +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/utils/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/utils/interactive/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/cli/utils/interactive/terminal_menu.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/menu.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/params.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/shared/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/shared/config/__init__.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/shared/config/globals.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/src/usecli/ui.py +0 -0
- {usecli-0.1.54 → usecli-0.1.56}/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.56"
|
|
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" }]
|
|
@@ -2,14 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import shutil
|
|
5
6
|
import sys
|
|
6
7
|
from importlib import import_module
|
|
8
|
+
from typing import Any, Optional, Sequence
|
|
7
9
|
|
|
8
10
|
import click
|
|
9
11
|
import typer
|
|
10
12
|
from click.exceptions import BadParameter, ClickException, Exit, UsageError
|
|
11
13
|
from typer.core import TyperGroup
|
|
12
14
|
|
|
15
|
+
try:
|
|
16
|
+
from typer._click.exceptions import BadParameter as TyperBadParameter # type: ignore[import-untyped]
|
|
17
|
+
from typer._click.exceptions import ClickException as TyperClickException # type: ignore[import-untyped]
|
|
18
|
+
from typer._click.exceptions import UsageError as TyperUsageError # type: ignore[import-untyped]
|
|
19
|
+
except ImportError:
|
|
20
|
+
TyperBadParameter = BadParameter
|
|
21
|
+
TyperClickException = ClickException
|
|
22
|
+
TyperUsageError = UsageError
|
|
23
|
+
|
|
13
24
|
from usecli.cli.config.colors import COLOR
|
|
14
25
|
from usecli.cli.core.base_command import BaseCommand
|
|
15
26
|
from usecli.cli.core.exceptions import UsecliBadParameter, UsecliUsageError
|
|
@@ -156,6 +167,31 @@ class PrefixMatchingGroup(TyperGroup):
|
|
|
156
167
|
|
|
157
168
|
return FilteredListCommand(cmd_name)
|
|
158
169
|
|
|
170
|
+
def main(
|
|
171
|
+
self,
|
|
172
|
+
args: Optional[Sequence[str]] = None,
|
|
173
|
+
prog_name: Optional[str] = None,
|
|
174
|
+
complete_var: Optional[str] = None,
|
|
175
|
+
standalone_mode: bool = True,
|
|
176
|
+
windows_expand_args: bool = True,
|
|
177
|
+
**extra: Any,
|
|
178
|
+
) -> Any:
|
|
179
|
+
"""Override main to disable standalone mode.
|
|
180
|
+
|
|
181
|
+
Click's default standalone_mode=True catches ClickException
|
|
182
|
+
internally and calls sys.exit(), preventing our custom error
|
|
183
|
+
handlers from running. Setting standalone_mode=False lets
|
|
184
|
+
exceptions propagate to our styled error handlers in invoke().
|
|
185
|
+
"""
|
|
186
|
+
return super().main(
|
|
187
|
+
args=args,
|
|
188
|
+
prog_name=prog_name,
|
|
189
|
+
complete_var=complete_var,
|
|
190
|
+
standalone_mode=False,
|
|
191
|
+
windows_expand_args=windows_expand_args,
|
|
192
|
+
**extra,
|
|
193
|
+
)
|
|
194
|
+
|
|
159
195
|
def invoke(self, ctx: click.Context) -> None:
|
|
160
196
|
"""Invoke the group with custom error handling.
|
|
161
197
|
|
|
@@ -169,15 +205,15 @@ class PrefixMatchingGroup(TyperGroup):
|
|
|
169
205
|
return super().invoke(ctx)
|
|
170
206
|
except Exit:
|
|
171
207
|
sys.exit(0)
|
|
172
|
-
except BadParameter as e:
|
|
208
|
+
except (BadParameter, TyperBadParameter) as e:
|
|
173
209
|
styled_error = UsecliBadParameter(e.message, ctx=e.ctx, param=e.param)
|
|
174
210
|
styled_error.show()
|
|
175
211
|
sys.exit(styled_error.exit_code)
|
|
176
|
-
except UsageError as e:
|
|
212
|
+
except (UsageError, TyperUsageError) as e:
|
|
177
213
|
styled_error = UsecliUsageError(e.message, ctx=e.ctx)
|
|
178
214
|
styled_error.show()
|
|
179
215
|
sys.exit(styled_error.exit_code)
|
|
180
|
-
except ClickException as e:
|
|
216
|
+
except (ClickException, TyperClickException) as e:
|
|
181
217
|
if hasattr(e, "show"):
|
|
182
218
|
e.show()
|
|
183
219
|
sys.exit(e.exit_code if hasattr(e, "exit_code") else 1)
|
|
@@ -247,8 +283,10 @@ def run_app(
|
|
|
247
283
|
raise typer.Exit()
|
|
248
284
|
|
|
249
285
|
if version:
|
|
286
|
+
config = get_config()
|
|
287
|
+
command_path = shutil.which(sys.argv[0]) or sys.argv[0]
|
|
250
288
|
console.print(
|
|
251
|
-
f"[bold
|
|
289
|
+
f"[bold {theme.SECONDARY}]{config.get('title')} {service.version}[/bold {theme.SECONDARY}] [{theme.INFO}]({command_path})[/{theme.INFO}]"
|
|
252
290
|
)
|
|
253
291
|
raise typer.Exit()
|
|
254
292
|
|
|
@@ -276,15 +314,15 @@ def main() -> None:
|
|
|
276
314
|
app()
|
|
277
315
|
except Exit:
|
|
278
316
|
sys.exit(0)
|
|
279
|
-
except BadParameter as e:
|
|
317
|
+
except (BadParameter, TyperBadParameter) as e:
|
|
280
318
|
styled_error = UsecliBadParameter(e.message, ctx=e.ctx, param=e.param)
|
|
281
319
|
styled_error.show()
|
|
282
320
|
sys.exit(styled_error.exit_code)
|
|
283
|
-
except UsageError as e:
|
|
321
|
+
except (UsageError, TyperUsageError) as e:
|
|
284
322
|
styled_error = UsecliUsageError(e.message, ctx=e.ctx)
|
|
285
323
|
styled_error.show()
|
|
286
324
|
sys.exit(styled_error.exit_code)
|
|
287
|
-
except ClickException as e:
|
|
325
|
+
except (ClickException, TyperClickException) as e:
|
|
288
326
|
if hasattr(e, "show"):
|
|
289
327
|
e.show()
|
|
290
328
|
sys.exit(e.exit_code if hasattr(e, "exit_code") else 1)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
|
-
from typing import TYPE_CHECKING, Any, ClassVar
|
|
6
|
+
from typing import TYPE_CHECKING, Any, ClassVar
|
|
7
7
|
|
|
8
8
|
import typer
|
|
9
9
|
from click.exceptions import Exit
|
|
@@ -192,42 +192,6 @@ class CustomHelpCommand(TyperCommand):
|
|
|
192
192
|
for param in getattr(self, "params", [])
|
|
193
193
|
)
|
|
194
194
|
|
|
195
|
-
def main(
|
|
196
|
-
self,
|
|
197
|
-
args: Optional[Sequence[str]] = None,
|
|
198
|
-
prog_name: Optional[str] = None,
|
|
199
|
-
complete_var: Optional[str] = None,
|
|
200
|
-
standalone_mode: bool = True,
|
|
201
|
-
windows_expand_args: bool = True,
|
|
202
|
-
**extra: Any,
|
|
203
|
-
) -> Any:
|
|
204
|
-
"""Override main to disable standalone mode.
|
|
205
|
-
|
|
206
|
-
Click's default standalone_mode=True catches ClickException
|
|
207
|
-
internally and calls sys.exit(), preventing our custom error
|
|
208
|
-
handlers from running. Setting standalone_mode=False lets
|
|
209
|
-
exceptions propagate to our styled error handlers.
|
|
210
|
-
|
|
211
|
-
Args:
|
|
212
|
-
args: Command-line arguments.
|
|
213
|
-
prog_name: Program name for help display.
|
|
214
|
-
complete_var: Shell completion variable name.
|
|
215
|
-
standalone_mode: Must be False for custom error handling.
|
|
216
|
-
windows_expand_args: Windows argument expansion flag.
|
|
217
|
-
**extra: Additional context arguments.
|
|
218
|
-
|
|
219
|
-
Returns:
|
|
220
|
-
The command return value.
|
|
221
|
-
"""
|
|
222
|
-
return super().main(
|
|
223
|
-
args=args,
|
|
224
|
-
prog_name=prog_name,
|
|
225
|
-
complete_var=complete_var,
|
|
226
|
-
standalone_mode=False,
|
|
227
|
-
windows_expand_args=windows_expand_args,
|
|
228
|
-
**extra,
|
|
229
|
-
)
|
|
230
|
-
|
|
231
195
|
def invoke(self, ctx: ClickContext) -> Any:
|
|
232
196
|
interactive = ctx.params.pop("interactive", False)
|
|
233
197
|
if interactive:
|
|
@@ -7,6 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
import importlib.metadata
|
|
9
9
|
import importlib.util
|
|
10
|
+
import json
|
|
10
11
|
import os
|
|
11
12
|
import sys
|
|
12
13
|
from pathlib import Path
|
|
@@ -138,6 +139,8 @@ class ConfigManager:
|
|
|
138
139
|
):
|
|
139
140
|
detected_root = config_parent
|
|
140
141
|
self.project_root: Path = (detected_root or start_dir).resolve()
|
|
142
|
+
if self._is_in_venv(self.project_root):
|
|
143
|
+
self.project_root = start_dir.resolve()
|
|
141
144
|
self._config: dict[str, Any] = {}
|
|
142
145
|
self._overrides: dict[str, Any] = {}
|
|
143
146
|
self._load_config()
|
|
@@ -279,9 +282,26 @@ class ConfigManager:
|
|
|
279
282
|
|
|
280
283
|
@staticmethod
|
|
281
284
|
def _find_usecli_config_in_package() -> Path | None:
|
|
282
|
-
|
|
285
|
+
package_name = _get_package_name()
|
|
286
|
+
spec = importlib.util.find_spec(package_name)
|
|
283
287
|
if spec is None or not spec.submodule_search_locations:
|
|
284
288
|
return None
|
|
289
|
+
|
|
290
|
+
command_name = ConfigManager._get_command_name()
|
|
291
|
+
aliases = ConfigManager._get_console_script_aliases(command_name)
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
dist = importlib.metadata.distribution(package_name)
|
|
295
|
+
source_root = ConfigManager._resolve_editable_source_root(dist)
|
|
296
|
+
if source_root:
|
|
297
|
+
source_config = ConfigManager._search_source_for_config(
|
|
298
|
+
source_root, command_name, aliases
|
|
299
|
+
)
|
|
300
|
+
if source_config:
|
|
301
|
+
return source_config
|
|
302
|
+
except Exception:
|
|
303
|
+
pass
|
|
304
|
+
|
|
285
305
|
for location in spec.submodule_search_locations:
|
|
286
306
|
package_root = Path(location)
|
|
287
307
|
if not package_root.exists() or not package_root.is_dir():
|
|
@@ -289,8 +309,6 @@ class ConfigManager:
|
|
|
289
309
|
candidates = [
|
|
290
310
|
path for path in package_root.rglob(USECLI_CONFIG_TOML) if path.exists()
|
|
291
311
|
]
|
|
292
|
-
command_name = ConfigManager._get_command_name()
|
|
293
|
-
aliases = ConfigManager._get_console_script_aliases(command_name)
|
|
294
312
|
if command_name:
|
|
295
313
|
candidates = [
|
|
296
314
|
path
|
|
@@ -311,6 +329,22 @@ class ConfigManager:
|
|
|
311
329
|
spec = importlib.util.find_spec(package_name)
|
|
312
330
|
if spec is None or not spec.submodule_search_locations:
|
|
313
331
|
return None
|
|
332
|
+
|
|
333
|
+
command_name = cls._get_command_name()
|
|
334
|
+
aliases = cls._get_console_script_aliases(command_name)
|
|
335
|
+
|
|
336
|
+
try:
|
|
337
|
+
dist = importlib.metadata.distribution(package_name)
|
|
338
|
+
source_root = cls._resolve_editable_source_root(dist)
|
|
339
|
+
if source_root:
|
|
340
|
+
source_config = cls._search_source_for_config(
|
|
341
|
+
source_root, command_name, aliases
|
|
342
|
+
)
|
|
343
|
+
if source_config:
|
|
344
|
+
return source_config
|
|
345
|
+
except Exception:
|
|
346
|
+
pass
|
|
347
|
+
|
|
314
348
|
for location in spec.submodule_search_locations:
|
|
315
349
|
package_root = Path(location)
|
|
316
350
|
if not package_root.exists() or not package_root.is_dir():
|
|
@@ -318,8 +352,6 @@ class ConfigManager:
|
|
|
318
352
|
candidates = [
|
|
319
353
|
path for path in package_root.rglob(USECLI_CONFIG_TOML) if path.exists()
|
|
320
354
|
]
|
|
321
|
-
command_name = cls._get_command_name()
|
|
322
|
-
aliases = cls._get_console_script_aliases(command_name)
|
|
323
355
|
if command_name:
|
|
324
356
|
candidates = [
|
|
325
357
|
path
|
|
@@ -362,7 +394,15 @@ class ConfigManager:
|
|
|
362
394
|
normalized = dist_name.replace("-", "_")
|
|
363
395
|
if normalized not in candidates:
|
|
364
396
|
candidates.append(normalized)
|
|
397
|
+
aliases = cls._get_console_script_aliases(command_name)
|
|
365
398
|
for package_name in candidates:
|
|
399
|
+
source_root = cls._resolve_editable_source_root(dist)
|
|
400
|
+
if source_root:
|
|
401
|
+
source_config = cls._search_source_for_config(
|
|
402
|
+
source_root, command_name, aliases
|
|
403
|
+
)
|
|
404
|
+
if source_config:
|
|
405
|
+
return source_config
|
|
366
406
|
match = cls._find_usecli_config_in_named_package(package_name)
|
|
367
407
|
if match:
|
|
368
408
|
return match
|
|
@@ -471,6 +511,71 @@ class ConfigManager:
|
|
|
471
511
|
aliases = {command_name}
|
|
472
512
|
return normalized in aliases
|
|
473
513
|
|
|
514
|
+
@staticmethod
|
|
515
|
+
def _is_in_venv(path: Path) -> bool:
|
|
516
|
+
resolved = path.resolve()
|
|
517
|
+
return any(part in ConfigManager._SKIP_DIRS for part in resolved.parts)
|
|
518
|
+
|
|
519
|
+
@staticmethod
|
|
520
|
+
def _resolve_editable_source_root(
|
|
521
|
+
dist: importlib.metadata.Distribution,
|
|
522
|
+
) -> Path | None:
|
|
523
|
+
"""Resolve the source directory for an editable-installed package.
|
|
524
|
+
|
|
525
|
+
Reads ``direct_url.json`` from the distribution's metadata to find the
|
|
526
|
+
local source tree. Returns the source root or ``None`` when the
|
|
527
|
+
distribution is not an editable install or the source no longer exists.
|
|
528
|
+
"""
|
|
529
|
+
try:
|
|
530
|
+
text = dist.read_text("direct_url.json")
|
|
531
|
+
except Exception:
|
|
532
|
+
return None
|
|
533
|
+
if not text:
|
|
534
|
+
return None
|
|
535
|
+
try:
|
|
536
|
+
data = json.loads(text)
|
|
537
|
+
except (json.JSONDecodeError, TypeError):
|
|
538
|
+
return None
|
|
539
|
+
if not isinstance(data, dict):
|
|
540
|
+
return None
|
|
541
|
+
if data.get("dir_info", {}).get("editable") is not True:
|
|
542
|
+
return None
|
|
543
|
+
url = data.get("url", "")
|
|
544
|
+
if not url:
|
|
545
|
+
return None
|
|
546
|
+
# ``url`` is a ``file://`` URI.
|
|
547
|
+
if url.startswith("file://"):
|
|
548
|
+
url = url[len("file://") :]
|
|
549
|
+
source = Path(url)
|
|
550
|
+
if source.exists() and source.is_dir():
|
|
551
|
+
return source.resolve()
|
|
552
|
+
return None
|
|
553
|
+
|
|
554
|
+
@staticmethod
|
|
555
|
+
def _search_source_for_config(
|
|
556
|
+
source_root: Path,
|
|
557
|
+
command_name: str | None,
|
|
558
|
+
aliases: set[str] | None,
|
|
559
|
+
) -> Path | None:
|
|
560
|
+
"""Search a source tree for a ``usecli.config.toml`` that matches."""
|
|
561
|
+
if not source_root.exists() or not source_root.is_dir():
|
|
562
|
+
return None
|
|
563
|
+
candidates = [
|
|
564
|
+
p
|
|
565
|
+
for p in source_root.rglob(USECLI_CONFIG_TOML)
|
|
566
|
+
if not any(part in ConfigManager._SKIP_DIRS for part in p.parts)
|
|
567
|
+
]
|
|
568
|
+
if command_name:
|
|
569
|
+
candidates = [
|
|
570
|
+
p
|
|
571
|
+
for p in candidates
|
|
572
|
+
if ConfigManager._config_matches_command(p, command_name, aliases)
|
|
573
|
+
]
|
|
574
|
+
if not candidates:
|
|
575
|
+
return None
|
|
576
|
+
candidates.sort(key=lambda p: (len(p.parts), str(p)))
|
|
577
|
+
return candidates[0]
|
|
578
|
+
|
|
474
579
|
def get(self, key: str, default: Any = None) -> Any:
|
|
475
580
|
"""Get a configuration value using dot notation.
|
|
476
581
|
|
|
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.54 → usecli-0.1.56}/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
|