falyx 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.
- {falyx-0.1.54 → falyx-0.1.56}/PKG-INFO +1 -1
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/select_file_action.py +5 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/command.py +7 -1
- falyx-0.1.56/falyx/completer.py +47 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/falyx.py +3 -14
- falyx-0.1.56/falyx/falyx_completer.py +128 -0
- falyx-0.1.56/falyx/parser/.pytyped +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/parser/command_argument_parser.py +73 -21
- falyx-0.1.56/falyx/version.py +1 -0
- {falyx-0.1.54 → falyx-0.1.56}/pyproject.toml +1 -1
- falyx-0.1.54/falyx/version.py +0 -1
- {falyx-0.1.54 → falyx-0.1.56}/LICENSE +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/README.md +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/.pytyped +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/__init__.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/__main__.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/.pytyped +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/__init__.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/action_factory.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/action_group.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/action_mixins.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/action_types.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/base_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/chained_action.py +0 -0
- /falyx-0.1.54/falyx/parser/.pytyped → /falyx-0.1.56/falyx/action/confirm_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/fallback_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/http_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/io_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/literal_input_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/load_file_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/menu_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/process_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/process_pool_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/prompt_menu_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/save_file_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/selection_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/shell_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/signal_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/action/user_input_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/bottom_bar.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/config.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/context.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/debug.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/exceptions.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/execution_registry.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/hook_manager.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/hooks.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/init.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/logger.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/menu.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/options_manager.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/parser/__init__.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/parser/argument.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/parser/argument_action.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/parser/parsers.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/parser/signature.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/parser/utils.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/prompt_utils.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/protocols.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/retry.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/retry_utils.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/selection.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/signals.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/tagged_table.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/themes/__init__.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/themes/colors.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/utils.py +0 -0
- {falyx-0.1.54 → falyx-0.1.56}/falyx/validators.py +0 -0
@@ -165,6 +165,11 @@ class SelectFileAction(BaseAction):
|
|
165
165
|
try:
|
166
166
|
await self.hooks.trigger(HookType.BEFORE, context)
|
167
167
|
|
168
|
+
if not self.directory.exists():
|
169
|
+
raise FileNotFoundError(f"Directory {self.directory} does not exist.")
|
170
|
+
elif not self.directory.is_dir():
|
171
|
+
raise NotADirectoryError(f"{self.directory} is not a directory.")
|
172
|
+
|
168
173
|
files = [
|
169
174
|
file
|
170
175
|
for file in self.directory.iterdir()
|
@@ -91,6 +91,12 @@ class Command(BaseModel):
|
|
91
91
|
logging_hooks (bool): Whether to attach logging hooks automatically.
|
92
92
|
options_manager (OptionsManager): Manages global command-line options.
|
93
93
|
arg_parser (CommandArgumentParser): Parses command arguments.
|
94
|
+
arguments (list[dict[str, Any]]): Argument definitions for the command.
|
95
|
+
argument_config (Callable[[CommandArgumentParser], None] | None): Function to configure arguments
|
96
|
+
for the command parser.
|
97
|
+
arg_metadata (dict[str, str | dict[str, Any]]): Metadata for arguments,
|
98
|
+
such as help text or choices.
|
99
|
+
simple_help_signature (bool): Whether to use a simplified help signature.
|
94
100
|
custom_parser (ArgParserProtocol | None): Custom argument parser.
|
95
101
|
custom_help (Callable[[], str | None] | None): Custom help message generator.
|
96
102
|
auto_args (bool): Automatically infer arguments from the action.
|
@@ -227,7 +233,7 @@ class Command(BaseModel):
|
|
227
233
|
if self.logging_hooks and isinstance(self.action, BaseAction):
|
228
234
|
register_debug_hooks(self.action.hooks)
|
229
235
|
|
230
|
-
if self.arg_parser is None:
|
236
|
+
if self.arg_parser is None and not self.custom_parser:
|
231
237
|
self.arg_parser = CommandArgumentParser(
|
232
238
|
command_key=self.key,
|
233
239
|
command_description=self.description,
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import shlex
|
4
|
+
from typing import TYPE_CHECKING, Iterable
|
5
|
+
|
6
|
+
from prompt_toolkit.completion import Completer, Completion
|
7
|
+
from prompt_toolkit.document import Document
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from falyx import Falyx
|
11
|
+
|
12
|
+
|
13
|
+
class FalyxCompleter(Completer):
|
14
|
+
"""Completer for Falyx commands."""
|
15
|
+
|
16
|
+
def __init__(self, falyx: "Falyx"):
|
17
|
+
self.falyx = falyx
|
18
|
+
|
19
|
+
def get_completions(self, document: Document, complete_event) -> Iterable[Completion]:
|
20
|
+
text = document.text_before_cursor
|
21
|
+
try:
|
22
|
+
tokens = shlex.split(text)
|
23
|
+
cursor_at_end_of_token = document.text_before_cursor.endswith((" ", "\t"))
|
24
|
+
except ValueError:
|
25
|
+
return
|
26
|
+
|
27
|
+
if not tokens or (len(tokens) == 1 and not cursor_at_end_of_token):
|
28
|
+
# Suggest command keys and aliases
|
29
|
+
yield from self._suggest_commands(tokens[0] if tokens else "")
|
30
|
+
return
|
31
|
+
|
32
|
+
def _suggest_commands(self, prefix: str) -> Iterable[Completion]:
|
33
|
+
prefix = prefix.upper()
|
34
|
+
keys = [self.falyx.exit_command.key]
|
35
|
+
keys.extend(self.falyx.exit_command.aliases)
|
36
|
+
if self.falyx.history_command:
|
37
|
+
keys.append(self.falyx.history_command.key)
|
38
|
+
keys.extend(self.falyx.history_command.aliases)
|
39
|
+
if self.falyx.help_command:
|
40
|
+
keys.append(self.falyx.help_command.key)
|
41
|
+
keys.extend(self.falyx.help_command.aliases)
|
42
|
+
for cmd in self.falyx.commands.values():
|
43
|
+
keys.append(cmd.key)
|
44
|
+
keys.extend(cmd.aliases)
|
45
|
+
for key in keys:
|
46
|
+
if key.upper().startswith(prefix):
|
47
|
+
yield Completion(key, start_position=-len(prefix))
|
@@ -32,7 +32,6 @@ from functools import cached_property
|
|
32
32
|
from typing import Any, Callable
|
33
33
|
|
34
34
|
from prompt_toolkit import PromptSession
|
35
|
-
from prompt_toolkit.completion import WordCompleter
|
36
35
|
from prompt_toolkit.formatted_text import AnyFormattedText
|
37
36
|
from prompt_toolkit.key_binding import KeyBindings
|
38
37
|
from prompt_toolkit.patch_stdout import patch_stdout
|
@@ -46,6 +45,7 @@ from falyx.action.action import Action
|
|
46
45
|
from falyx.action.base_action import BaseAction
|
47
46
|
from falyx.bottom_bar import BottomBar
|
48
47
|
from falyx.command import Command
|
48
|
+
from falyx.completer import FalyxCompleter
|
49
49
|
from falyx.context import ExecutionContext
|
50
50
|
from falyx.debug import log_after, log_before, log_error, log_success
|
51
51
|
from falyx.exceptions import (
|
@@ -413,20 +413,9 @@ class Falyx:
|
|
413
413
|
arg_parser=parser,
|
414
414
|
)
|
415
415
|
|
416
|
-
def _get_completer(self) ->
|
416
|
+
def _get_completer(self) -> FalyxCompleter:
|
417
417
|
"""Completer to provide auto-completion for the menu commands."""
|
418
|
-
|
419
|
-
keys.extend(self.exit_command.aliases)
|
420
|
-
if self.history_command:
|
421
|
-
keys.append(self.history_command.key)
|
422
|
-
keys.extend(self.history_command.aliases)
|
423
|
-
if self.help_command:
|
424
|
-
keys.append(self.help_command.key)
|
425
|
-
keys.extend(self.help_command.aliases)
|
426
|
-
for cmd in self.commands.values():
|
427
|
-
keys.append(cmd.key)
|
428
|
-
keys.extend(cmd.aliases)
|
429
|
-
return WordCompleter(keys, ignore_case=True)
|
418
|
+
return FalyxCompleter(self)
|
430
419
|
|
431
420
|
def _get_validator_error_message(self) -> str:
|
432
421
|
"""Validator to check if the input is a valid command or toggle key."""
|
@@ -0,0 +1,128 @@
|
|
1
|
+
from collections import Counter
|
2
|
+
from prompt_toolkit.completion import Completer, Completion
|
3
|
+
from prompt_toolkit.document import Document
|
4
|
+
from typing import Iterable, Set, Optional
|
5
|
+
import shlex
|
6
|
+
|
7
|
+
from falyx.command import Command
|
8
|
+
from falyx.parser.command_argument_parser import CommandArgumentParser
|
9
|
+
from falyx.parser.argument import Argument
|
10
|
+
from falyx.parser.argument_action import ArgumentAction
|
11
|
+
|
12
|
+
class FalyxCompleter(Completer):
|
13
|
+
"""Completer for Falyx commands and their arguments."""
|
14
|
+
def __init__(self, falyx: "Falyx"):
|
15
|
+
self.falyx = falyx
|
16
|
+
self._used_args: Set[str] = set()
|
17
|
+
self._used_args_counter: Counter = Counter()
|
18
|
+
|
19
|
+
def get_completions(self, document: Document, complete_event) -> Iterable[Completion]:
|
20
|
+
text = document.text_before_cursor
|
21
|
+
try:
|
22
|
+
tokens = shlex.split(text)
|
23
|
+
cursor_at_end_of_token = document.text_before_cursor.endswith((' ', '\t'))
|
24
|
+
except ValueError:
|
25
|
+
return
|
26
|
+
|
27
|
+
if not tokens or (len(tokens) == 1 and not cursor_at_end_of_token):
|
28
|
+
# Suggest command keys and aliases
|
29
|
+
yield from self._suggest_commands(tokens[0] if tokens else "")
|
30
|
+
return
|
31
|
+
|
32
|
+
command = self._match_command(tokens[0])
|
33
|
+
if not command:
|
34
|
+
return
|
35
|
+
|
36
|
+
if command.arg_parser is None:
|
37
|
+
return
|
38
|
+
|
39
|
+
self._set_used_args(tokens, command)
|
40
|
+
|
41
|
+
next_arg = self._next_expected_argument(tokens, command.arg_parser)
|
42
|
+
|
43
|
+
if next_arg:
|
44
|
+
# Positional arguments or required flagged arguments
|
45
|
+
yield from self._suggest_argument(next_arg, document)
|
46
|
+
else:
|
47
|
+
# Optional arguments
|
48
|
+
for arg in command.arg_parser._keyword.values():
|
49
|
+
if not self._arg_already_used(arg.dest):
|
50
|
+
yield from self._suggest_argument(arg, document)
|
51
|
+
|
52
|
+
def _set_used_args(self, tokens: list[str], command: Command) -> None:
|
53
|
+
"""Extracts used argument flags from the provided tokens."""
|
54
|
+
if not command.arg_parser:
|
55
|
+
return
|
56
|
+
self._used_args.clear()
|
57
|
+
self._used_args_counter.clear()
|
58
|
+
for token in tokens[1:]:
|
59
|
+
if token.startswith('-'):
|
60
|
+
if keyword_argument := command.arg_parser._keyword.get(token):
|
61
|
+
self._used_args_counter[keyword_argument.dest] += 1
|
62
|
+
if isinstance(keyword_argument.nargs, int) and self._used_args_counter[keyword_argument.dest] > keyword_argument.nargs:
|
63
|
+
continue
|
64
|
+
elif isinstance(keyword_argument.nargs, str) and keyword_argument.nargs in ("?"):
|
65
|
+
self._used_args.add(keyword_argument.dest)
|
66
|
+
else:
|
67
|
+
self._used_args.add(keyword_argument.dest)
|
68
|
+
else:
|
69
|
+
# Handle positional arguments
|
70
|
+
if command.arg_parser._positional:
|
71
|
+
for arg in command.arg_parser._positional.values():
|
72
|
+
if arg.dest not in self._used_args:
|
73
|
+
self._used_args.add(arg.dest)
|
74
|
+
break
|
75
|
+
print(f"Used args: {self._used_args}, Counter: {self._used_args_counter}")
|
76
|
+
|
77
|
+
def _suggest_commands(self, prefix: str) -> Iterable[Completion]:
|
78
|
+
prefix = prefix.upper()
|
79
|
+
seen = set()
|
80
|
+
for cmd in self.falyx.commands.values():
|
81
|
+
for key in [cmd.key] + cmd.aliases:
|
82
|
+
if key.upper().startswith(prefix) and key not in seen:
|
83
|
+
yield Completion(key, start_position=-len(prefix))
|
84
|
+
seen.add(key)
|
85
|
+
|
86
|
+
def _match_command(self, token: str) -> Optional[Command]:
|
87
|
+
token = token.lstrip("?").upper()
|
88
|
+
return self.falyx._name_map.get(token)
|
89
|
+
|
90
|
+
def _next_expected_argument(
|
91
|
+
self, tokens: list[str], parser: CommandArgumentParser
|
92
|
+
) -> Optional[Argument]:
|
93
|
+
"""Determine the next expected argument based on the current tokens."""
|
94
|
+
# Positional arguments first
|
95
|
+
for arg in parser._positional.values():
|
96
|
+
if arg.dest not in self._used_args:
|
97
|
+
return arg
|
98
|
+
|
99
|
+
# Then required keyword arguments
|
100
|
+
for arg in parser._keyword_list:
|
101
|
+
if arg.required and not self._arg_already_used(arg.dest):
|
102
|
+
return arg
|
103
|
+
|
104
|
+
return None
|
105
|
+
|
106
|
+
def _arg_already_used(self, dest: str) -> bool:
|
107
|
+
print(f"Checking if argument '{dest}' is already used: {dest in self._used_args} - Used args: {self._used_args}")
|
108
|
+
return dest in self._used_args
|
109
|
+
|
110
|
+
def _suggest_argument(self, arg: Argument, document: Document) -> Iterable[Completion]:
|
111
|
+
if not arg.positional:
|
112
|
+
for flag in arg.flags:
|
113
|
+
yield Completion(flag, start_position=0)
|
114
|
+
|
115
|
+
if arg.choices:
|
116
|
+
for choice in arg.choices:
|
117
|
+
yield Completion(
|
118
|
+
choice,
|
119
|
+
start_position=0,
|
120
|
+
display=f"{arg.dest}={choice}"
|
121
|
+
)
|
122
|
+
|
123
|
+
if arg.default is not None and arg.action == ArgumentAction.STORE:
|
124
|
+
yield Completion(
|
125
|
+
str(arg.default),
|
126
|
+
start_position=0,
|
127
|
+
display=f"{arg.dest} (default: {arg.default})"
|
128
|
+
)
|
File without changes
|
@@ -7,7 +7,6 @@ from typing import Any, Iterable
|
|
7
7
|
|
8
8
|
from rich.console import Console
|
9
9
|
from rich.markup import escape
|
10
|
-
from rich.text import Text
|
11
10
|
|
12
11
|
from falyx.action.base_action import BaseAction
|
13
12
|
from falyx.exceptions import CommandArgumentError
|
@@ -466,6 +465,10 @@ class CommandArgumentParser:
|
|
466
465
|
or isinstance(next_spec.nargs, str)
|
467
466
|
and next_spec.nargs in ("+", "*", "?")
|
468
467
|
), f"Invalid nargs value: {spec.nargs}"
|
468
|
+
|
469
|
+
if next_spec.default:
|
470
|
+
continue
|
471
|
+
|
469
472
|
if next_spec.nargs is None:
|
470
473
|
min_required += 1
|
471
474
|
elif isinstance(next_spec.nargs, int):
|
@@ -473,9 +476,9 @@ class CommandArgumentParser:
|
|
473
476
|
elif next_spec.nargs == "+":
|
474
477
|
min_required += 1
|
475
478
|
elif next_spec.nargs == "?":
|
476
|
-
|
479
|
+
continue
|
477
480
|
elif next_spec.nargs == "*":
|
478
|
-
|
481
|
+
continue
|
479
482
|
|
480
483
|
slice_args = args[i:] if is_last else args[i : i + (remaining - min_required)]
|
481
484
|
values, new_i = self._consume_nargs(slice_args, 0, spec)
|
@@ -484,9 +487,23 @@ class CommandArgumentParser:
|
|
484
487
|
try:
|
485
488
|
typed = [coerce_value(value, spec.type) for value in values]
|
486
489
|
except Exception as error:
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
+
if len(args[i - new_i :]) == 1 and args[i - new_i].startswith("-"):
|
491
|
+
token = args[i - new_i]
|
492
|
+
valid_flags = [
|
493
|
+
flag for flag in self._flag_map if flag.startswith(token)
|
494
|
+
]
|
495
|
+
if valid_flags:
|
496
|
+
raise CommandArgumentError(
|
497
|
+
f"Unrecognized option '{token}'. Did you mean one of: {', '.join(valid_flags)}?"
|
498
|
+
) from error
|
499
|
+
else:
|
500
|
+
raise CommandArgumentError(
|
501
|
+
f"Unrecognized option '{token}'. Use --help to see available options."
|
502
|
+
) from error
|
503
|
+
else:
|
504
|
+
raise CommandArgumentError(
|
505
|
+
f"Invalid value for '{spec.dest}': {error}"
|
506
|
+
) from error
|
490
507
|
if spec.action == ArgumentAction.ACTION:
|
491
508
|
assert isinstance(
|
492
509
|
spec.resolver, BaseAction
|
@@ -497,6 +514,8 @@ class CommandArgumentParser:
|
|
497
514
|
raise CommandArgumentError(
|
498
515
|
f"[{spec.dest}] Action failed: {error}"
|
499
516
|
) from error
|
517
|
+
elif not typed and spec.default:
|
518
|
+
result[spec.dest] = spec.default
|
500
519
|
elif spec.action == ArgumentAction.APPEND:
|
501
520
|
assert result.get(spec.dest) is not None, "dest should not be None"
|
502
521
|
if spec.nargs is None:
|
@@ -515,10 +534,22 @@ class CommandArgumentParser:
|
|
515
534
|
consumed_positional_indicies.add(j)
|
516
535
|
|
517
536
|
if i < len(args):
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
537
|
+
if len(args[i:]) == 1 and args[i].startswith("-"):
|
538
|
+
token = args[i]
|
539
|
+
valid_flags = [flag for flag in self._flag_map if flag.startswith(token)]
|
540
|
+
if valid_flags:
|
541
|
+
raise CommandArgumentError(
|
542
|
+
f"Unrecognized option '{token}'. Did you mean one of: {', '.join(valid_flags)}?"
|
543
|
+
)
|
544
|
+
else:
|
545
|
+
raise CommandArgumentError(
|
546
|
+
f"Unrecognized option '{token}'. Use --help to see available options."
|
547
|
+
)
|
548
|
+
else:
|
549
|
+
plural = "s" if len(args[i:]) > 1 else ""
|
550
|
+
raise CommandArgumentError(
|
551
|
+
f"Unexpected positional argument{plural}: {', '.join(args[i:])}"
|
552
|
+
)
|
522
553
|
|
523
554
|
return i
|
524
555
|
|
@@ -624,8 +655,22 @@ class CommandArgumentParser:
|
|
624
655
|
f"Invalid value for '{spec.dest}': {error}"
|
625
656
|
) from error
|
626
657
|
if not typed_values and spec.nargs not in ("*", "?"):
|
658
|
+
choices = []
|
659
|
+
if spec.default:
|
660
|
+
choices.append(f"default={spec.default!r}")
|
661
|
+
if spec.choices:
|
662
|
+
choices.append(f"choices={spec.choices!r}")
|
663
|
+
if choices:
|
664
|
+
choices_text = ", ".join(choices)
|
665
|
+
raise CommandArgumentError(
|
666
|
+
f"Argument '{spec.dest}' requires a value. {choices_text}"
|
667
|
+
)
|
668
|
+
if spec.nargs is None:
|
669
|
+
raise CommandArgumentError(
|
670
|
+
f"Enter a {spec.type.__name__} value for '{spec.dest}'"
|
671
|
+
)
|
627
672
|
raise CommandArgumentError(
|
628
|
-
f"
|
673
|
+
f"Argument '{spec.dest}' requires a value. Expected {spec.nargs} values."
|
629
674
|
)
|
630
675
|
if spec.nargs in (None, 1, "?") and spec.action != ArgumentAction.APPEND:
|
631
676
|
result[spec.dest] = (
|
@@ -637,7 +682,15 @@ class CommandArgumentParser:
|
|
637
682
|
i = new_i
|
638
683
|
elif token.startswith("-"):
|
639
684
|
# Handle unrecognized option
|
640
|
-
|
685
|
+
valid_flags = [flag for flag in self._flag_map if flag.startswith(token)]
|
686
|
+
if valid_flags:
|
687
|
+
raise CommandArgumentError(
|
688
|
+
f"Unrecognized option '{token}'. Did you mean one of: {', '.join(valid_flags)}?"
|
689
|
+
)
|
690
|
+
else:
|
691
|
+
raise CommandArgumentError(
|
692
|
+
f"Unrecognized option '{token}'. Use --help to see available options."
|
693
|
+
)
|
641
694
|
else:
|
642
695
|
# Get the next flagged argument index if it exists
|
643
696
|
next_flagged_index = -1
|
@@ -645,8 +698,6 @@ class CommandArgumentParser:
|
|
645
698
|
if arg in self._keyword:
|
646
699
|
next_flagged_index = index
|
647
700
|
break
|
648
|
-
print(f"next_flagged_index: {next_flagged_index}")
|
649
|
-
print(f"{self._keyword_list=}")
|
650
701
|
if next_flagged_index == -1:
|
651
702
|
next_flagged_index = len(args)
|
652
703
|
args_consumed = await self._consume_all_positional_args(
|
@@ -694,7 +745,10 @@ class CommandArgumentParser:
|
|
694
745
|
if spec.dest == "help":
|
695
746
|
continue
|
696
747
|
if spec.required and not result.get(spec.dest):
|
697
|
-
|
748
|
+
help_text = f" help: {spec.help}" if spec.help else ""
|
749
|
+
raise CommandArgumentError(
|
750
|
+
f"Missing required argument {spec.dest}: {spec.get_choice_text()}{help_text}"
|
751
|
+
)
|
698
752
|
|
699
753
|
if spec.choices and result.get(spec.dest) not in spec.choices:
|
700
754
|
raise CommandArgumentError(
|
@@ -809,22 +863,20 @@ class CommandArgumentParser:
|
|
809
863
|
self.console.print("[bold]positional:[/bold]")
|
810
864
|
for arg in self._positional.values():
|
811
865
|
flags = arg.get_positional_text()
|
812
|
-
arg_line =
|
866
|
+
arg_line = f" {flags:<30} "
|
813
867
|
help_text = arg.help or ""
|
814
868
|
if help_text and len(flags) > 30:
|
815
869
|
help_text = f"\n{'':<33}{help_text}"
|
816
|
-
|
817
|
-
self.console.print(arg_line)
|
870
|
+
self.console.print(f"{arg_line}{help_text}")
|
818
871
|
self.console.print("[bold]options:[/bold]")
|
819
872
|
for arg in self._keyword_list:
|
820
873
|
flags = ", ".join(arg.flags)
|
821
874
|
flags_choice = f"{flags} {arg.get_choice_text()}"
|
822
|
-
arg_line =
|
875
|
+
arg_line = f" {flags_choice:<30} "
|
823
876
|
help_text = arg.help or ""
|
824
877
|
if help_text and len(flags_choice) > 30:
|
825
878
|
help_text = f"\n{'':<33}{help_text}"
|
826
|
-
|
827
|
-
self.console.print(arg_line)
|
879
|
+
self.console.print(f"{arg_line}{help_text}")
|
828
880
|
|
829
881
|
# Epilog
|
830
882
|
if self.help_epilog:
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.56"
|
falyx-0.1.54/falyx/version.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "0.1.54"
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|