falyx 0.1.43__py3-none-any.whl → 0.1.45__py3-none-any.whl
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/command.py +38 -4
- falyx/config.py +0 -9
- falyx/falyx.py +67 -59
- falyx/parsers/argparse.py +17 -8
- falyx/parsers/parsers.py +4 -0
- falyx/parsers/signature.py +2 -1
- falyx/parsers/utils.py +70 -1
- falyx/version.py +1 -1
- {falyx-0.1.43.dist-info → falyx-0.1.45.dist-info}/METADATA +2 -1
- {falyx-0.1.43.dist-info → falyx-0.1.45.dist-info}/RECORD +13 -13
- {falyx-0.1.43.dist-info → falyx-0.1.45.dist-info}/LICENSE +0 -0
- {falyx-0.1.43.dist-info → falyx-0.1.45.dist-info}/WHEEL +0 -0
- {falyx-0.1.43.dist-info → falyx-0.1.45.dist-info}/entry_points.txt +0 -0
falyx/command.py
CHANGED
@@ -128,13 +128,14 @@ class Command(BaseModel):
|
|
128
128
|
tags: list[str] = Field(default_factory=list)
|
129
129
|
logging_hooks: bool = False
|
130
130
|
options_manager: OptionsManager = Field(default_factory=OptionsManager)
|
131
|
-
arg_parser: CommandArgumentParser =
|
131
|
+
arg_parser: CommandArgumentParser | None = None
|
132
132
|
arguments: list[dict[str, Any]] = Field(default_factory=list)
|
133
133
|
argument_config: Callable[[CommandArgumentParser], None] | None = None
|
134
134
|
custom_parser: ArgParserProtocol | None = None
|
135
135
|
custom_help: Callable[[], str | None] | None = None
|
136
136
|
auto_args: bool = True
|
137
137
|
arg_metadata: dict[str, str | dict[str, Any]] = Field(default_factory=dict)
|
138
|
+
simple_help_signature: bool = False
|
138
139
|
|
139
140
|
_context: ExecutionContext | None = PrivateAttr(default=None)
|
140
141
|
|
@@ -166,6 +167,12 @@ class Command(BaseModel):
|
|
166
167
|
raw_args,
|
167
168
|
)
|
168
169
|
return ((), {})
|
170
|
+
if not isinstance(self.arg_parser, CommandArgumentParser):
|
171
|
+
logger.warning(
|
172
|
+
"[Command:%s] No argument parser configured, using default parsing.",
|
173
|
+
self.key,
|
174
|
+
)
|
175
|
+
return ((), {})
|
169
176
|
return await self.arg_parser.parse_args_split(
|
170
177
|
raw_args, from_validate=from_validate
|
171
178
|
)
|
@@ -182,7 +189,9 @@ class Command(BaseModel):
|
|
182
189
|
def get_argument_definitions(self) -> list[dict[str, Any]]:
|
183
190
|
if self.arguments:
|
184
191
|
return self.arguments
|
185
|
-
elif callable(self.argument_config)
|
192
|
+
elif callable(self.argument_config) and isinstance(
|
193
|
+
self.arg_parser, CommandArgumentParser
|
194
|
+
):
|
186
195
|
self.argument_config(self.arg_parser)
|
187
196
|
elif self.auto_args:
|
188
197
|
if isinstance(self.action, BaseAction):
|
@@ -218,8 +227,17 @@ class Command(BaseModel):
|
|
218
227
|
if self.logging_hooks and isinstance(self.action, BaseAction):
|
219
228
|
register_debug_hooks(self.action.hooks)
|
220
229
|
|
221
|
-
|
222
|
-
self.arg_parser
|
230
|
+
if self.arg_parser is None:
|
231
|
+
self.arg_parser = CommandArgumentParser(
|
232
|
+
command_key=self.key,
|
233
|
+
command_description=self.description,
|
234
|
+
command_style=self.style,
|
235
|
+
help_text=self.help_text,
|
236
|
+
help_epilogue=self.help_epilogue,
|
237
|
+
aliases=self.aliases,
|
238
|
+
)
|
239
|
+
for arg_def in self.get_argument_definitions():
|
240
|
+
self.arg_parser.add_argument(*arg_def.pop("flags"), **arg_def)
|
223
241
|
|
224
242
|
def _inject_options_manager(self) -> None:
|
225
243
|
"""Inject the options manager into the action if applicable."""
|
@@ -317,6 +335,22 @@ class Command(BaseModel):
|
|
317
335
|
options_text = self.arg_parser.get_options_text(plain_text=True)
|
318
336
|
return f" {command_keys_text:<20} {options_text} "
|
319
337
|
|
338
|
+
@property
|
339
|
+
def help_signature(self) -> str:
|
340
|
+
"""Generate a help signature for the command."""
|
341
|
+
if self.arg_parser and not self.simple_help_signature:
|
342
|
+
signature = [self.arg_parser.get_usage()]
|
343
|
+
signature.append(f" {self.help_text or self.description}")
|
344
|
+
if self.tags:
|
345
|
+
signature.append(f" [dim]Tags: {', '.join(self.tags)}[/dim]")
|
346
|
+
return "\n".join(signature).strip()
|
347
|
+
|
348
|
+
command_keys = " | ".join(
|
349
|
+
[f"[{self.style}]{self.key}[/{self.style}]"]
|
350
|
+
+ [f"[{self.style}]{alias}[/{self.style}]" for alias in self.aliases]
|
351
|
+
)
|
352
|
+
return f"{command_keys} {self.description}"
|
353
|
+
|
320
354
|
def log_summary(self) -> None:
|
321
355
|
if self._context:
|
322
356
|
self._context.log_summary()
|
falyx/config.py
CHANGED
@@ -118,14 +118,6 @@ def convert_commands(raw_commands: list[dict[str, Any]]) -> list[Command]:
|
|
118
118
|
commands = []
|
119
119
|
for entry in raw_commands:
|
120
120
|
raw_command = RawCommand(**entry)
|
121
|
-
parser = CommandArgumentParser(
|
122
|
-
command_key=raw_command.key,
|
123
|
-
command_description=raw_command.description,
|
124
|
-
command_style=raw_command.style,
|
125
|
-
help_text=raw_command.help_text,
|
126
|
-
help_epilogue=raw_command.help_epilogue,
|
127
|
-
aliases=raw_command.aliases,
|
128
|
-
)
|
129
121
|
commands.append(
|
130
122
|
Command.model_validate(
|
131
123
|
{
|
@@ -133,7 +125,6 @@ def convert_commands(raw_commands: list[dict[str, Any]]) -> list[Command]:
|
|
133
125
|
"action": wrap_if_needed(
|
134
126
|
import_action(raw_command.action), name=raw_command.description
|
135
127
|
),
|
136
|
-
"arg_parser": parser,
|
137
128
|
}
|
138
129
|
)
|
139
130
|
)
|
falyx/falyx.py
CHANGED
@@ -284,6 +284,7 @@ class Falyx:
|
|
284
284
|
action=Action("Exit", action=_noop),
|
285
285
|
aliases=["EXIT", "QUIT"],
|
286
286
|
style=OneColors.DARK_RED,
|
287
|
+
simple_help_signature=True,
|
287
288
|
)
|
288
289
|
|
289
290
|
def _get_history_command(self) -> Command:
|
@@ -294,60 +295,70 @@ class Falyx:
|
|
294
295
|
aliases=["HISTORY"],
|
295
296
|
action=Action(name="View Execution History", action=er.summary),
|
296
297
|
style=OneColors.DARK_YELLOW,
|
298
|
+
simple_help_signature=True,
|
297
299
|
)
|
298
300
|
|
299
|
-
async def _show_help(self):
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
help_text = command.help_text or command.description
|
308
|
-
table.add_row(
|
309
|
-
f"[{command.style}]{command.key}[/]",
|
310
|
-
", ".join(command.aliases) if command.aliases else "",
|
311
|
-
help_text,
|
312
|
-
", ".join(command.tags) if command.tags else "",
|
301
|
+
async def _show_help(self, tag: str = "") -> None:
|
302
|
+
if tag:
|
303
|
+
table = Table(
|
304
|
+
title=tag.upper(),
|
305
|
+
title_justify="left",
|
306
|
+
show_header=False,
|
307
|
+
box=box.SIMPLE,
|
308
|
+
show_footer=False,
|
313
309
|
)
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
310
|
+
tag_lower = tag.lower()
|
311
|
+
commands = [
|
312
|
+
command
|
313
|
+
for command in self.commands.values()
|
314
|
+
if any(tag_lower == tag.lower() for tag in command.tags)
|
315
|
+
]
|
316
|
+
for command in commands:
|
317
|
+
table.add_row(command.help_signature)
|
318
|
+
self.console.print(table)
|
319
|
+
return
|
320
|
+
else:
|
321
|
+
table = Table(
|
322
|
+
title="Help",
|
323
|
+
title_justify="left",
|
324
|
+
title_style=OneColors.LIGHT_YELLOW_b,
|
325
|
+
show_header=False,
|
326
|
+
show_footer=False,
|
327
|
+
box=box.SIMPLE,
|
326
328
|
)
|
327
|
-
|
329
|
+
for command in self.commands.values():
|
330
|
+
table.add_row(command.help_signature)
|
328
331
|
if self.help_command:
|
329
|
-
table.add_row(
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
self.console.print(table, justify="center")
|
336
|
-
if self.mode == FalyxMode.MENU:
|
337
|
-
self.console.print(
|
338
|
-
f"📦 Tip: '[{OneColors.LIGHT_YELLOW}]?[KEY][/]' to preview a command "
|
339
|
-
"before running it.\n",
|
340
|
-
justify="center",
|
341
|
-
)
|
332
|
+
table.add_row(self.help_command.help_signature)
|
333
|
+
if self.history_command:
|
334
|
+
table.add_row(self.history_command.help_signature)
|
335
|
+
table.add_row(self.exit_command.help_signature)
|
336
|
+
table.add_row(f"Tip: '[{OneColors.LIGHT_YELLOW}]?[KEY][/]' to preview a command ")
|
337
|
+
self.console.print(table)
|
342
338
|
|
343
339
|
def _get_help_command(self) -> Command:
|
344
340
|
"""Returns the help command for the menu."""
|
341
|
+
parser = CommandArgumentParser(
|
342
|
+
command_key="H",
|
343
|
+
command_description="Help",
|
344
|
+
command_style=OneColors.LIGHT_YELLOW,
|
345
|
+
aliases=["?", "HELP", "LIST"],
|
346
|
+
)
|
347
|
+
parser.add_argument(
|
348
|
+
"-t",
|
349
|
+
"--tag",
|
350
|
+
nargs="?",
|
351
|
+
default="",
|
352
|
+
help="Optional tag to filter commands by.",
|
353
|
+
)
|
345
354
|
return Command(
|
346
355
|
key="H",
|
347
|
-
aliases=["HELP", "
|
356
|
+
aliases=["?", "HELP", "LIST"],
|
348
357
|
description="Help",
|
358
|
+
help_text="Show this help menu",
|
349
359
|
action=Action("Help", self._show_help),
|
350
360
|
style=OneColors.LIGHT_YELLOW,
|
361
|
+
arg_parser=parser,
|
351
362
|
)
|
352
363
|
|
353
364
|
def _get_completer(self) -> WordCompleter:
|
@@ -568,7 +579,9 @@ class Falyx:
|
|
568
579
|
if not isinstance(submenu, Falyx):
|
569
580
|
raise NotAFalyxError("submenu must be an instance of Falyx.")
|
570
581
|
self._validate_command_key(key)
|
571
|
-
self.add_command(
|
582
|
+
self.add_command(
|
583
|
+
key, description, submenu.menu, style=style, simple_help_signature=True
|
584
|
+
)
|
572
585
|
if submenu.exit_command.key == "X":
|
573
586
|
submenu.update_exit_command(key="B", description="Back", aliases=["BACK"])
|
574
587
|
|
@@ -630,6 +643,7 @@ class Falyx:
|
|
630
643
|
custom_help: Callable[[], str | None] | None = None,
|
631
644
|
auto_args: bool = True,
|
632
645
|
arg_metadata: dict[str, str | dict[str, Any]] | None = None,
|
646
|
+
simple_help_signature: bool = False,
|
633
647
|
) -> Command:
|
634
648
|
"""Adds an command to the menu, preventing duplicates."""
|
635
649
|
self._validate_command_key(key)
|
@@ -640,15 +654,6 @@ class Falyx:
|
|
640
654
|
"arg_parser must be an instance of CommandArgumentParser."
|
641
655
|
)
|
642
656
|
arg_parser = arg_parser
|
643
|
-
else:
|
644
|
-
arg_parser = CommandArgumentParser(
|
645
|
-
command_key=key,
|
646
|
-
command_description=description,
|
647
|
-
command_style=style,
|
648
|
-
help_text=help_text,
|
649
|
-
help_epilogue=help_epilogue,
|
650
|
-
aliases=aliases,
|
651
|
-
)
|
652
657
|
|
653
658
|
command = Command(
|
654
659
|
key=key,
|
@@ -682,6 +687,7 @@ class Falyx:
|
|
682
687
|
custom_help=custom_help,
|
683
688
|
auto_args=auto_args,
|
684
689
|
arg_metadata=arg_metadata or {},
|
690
|
+
simple_help_signature=simple_help_signature,
|
685
691
|
)
|
686
692
|
|
687
693
|
if hooks:
|
@@ -706,16 +712,16 @@ class Falyx:
|
|
706
712
|
def get_bottom_row(self) -> list[str]:
|
707
713
|
"""Returns the bottom row of the table for displaying additional commands."""
|
708
714
|
bottom_row = []
|
709
|
-
if self.history_command:
|
710
|
-
bottom_row.append(
|
711
|
-
f"[{self.history_command.key}] [{self.history_command.style}]"
|
712
|
-
f"{self.history_command.description}"
|
713
|
-
)
|
714
715
|
if self.help_command:
|
715
716
|
bottom_row.append(
|
716
717
|
f"[{self.help_command.key}] [{self.help_command.style}]"
|
717
718
|
f"{self.help_command.description}"
|
718
719
|
)
|
720
|
+
if self.history_command:
|
721
|
+
bottom_row.append(
|
722
|
+
f"[{self.history_command.key}] [{self.history_command.style}]"
|
723
|
+
f"{self.history_command.description}"
|
724
|
+
)
|
719
725
|
bottom_row.append(
|
720
726
|
f"[{self.exit_command.key}] [{self.exit_command.style}]"
|
721
727
|
f"{self.exit_command.description}"
|
@@ -727,12 +733,14 @@ class Falyx:
|
|
727
733
|
Build the standard table layout. Developers can subclass or call this
|
728
734
|
in custom tables.
|
729
735
|
"""
|
730
|
-
table = Table(title=self.title, show_header=False, box=box.SIMPLE
|
736
|
+
table = Table(title=self.title, show_header=False, box=box.SIMPLE) # type: ignore[arg-type]
|
731
737
|
visible_commands = [item for item in self.commands.items() if not item[1].hidden]
|
738
|
+
space = self.console.width // self.columns
|
732
739
|
for chunk in chunks(visible_commands, self.columns):
|
733
740
|
row = []
|
734
741
|
for key, command in chunk:
|
735
|
-
|
742
|
+
cell = f"[{key}] [{command.style}]{command.description}"
|
743
|
+
row.append(f"{cell:<{space}}")
|
736
744
|
table.add_row(*row)
|
737
745
|
bottom_row = self.get_bottom_row()
|
738
746
|
for row in chunks(bottom_row, self.columns):
|
@@ -1076,7 +1084,7 @@ class Falyx:
|
|
1076
1084
|
self.register_all_with_debug_hooks()
|
1077
1085
|
|
1078
1086
|
if self.cli_args.command == "list":
|
1079
|
-
await self._show_help()
|
1087
|
+
await self._show_help(tag=self.cli_args.tag)
|
1080
1088
|
sys.exit(0)
|
1081
1089
|
|
1082
1090
|
if self.cli_args.command == "version" or self.cli_args.version:
|
falyx/parsers/argparse.py
CHANGED
@@ -12,6 +12,7 @@ from rich.text import Text
|
|
12
12
|
|
13
13
|
from falyx.action.base import BaseAction
|
14
14
|
from falyx.exceptions import CommandArgumentError
|
15
|
+
from falyx.parsers.utils import coerce_value
|
15
16
|
from falyx.signals import HelpSignal
|
16
17
|
|
17
18
|
|
@@ -290,7 +291,7 @@ class CommandArgumentParser:
|
|
290
291
|
for choice in choices:
|
291
292
|
if not isinstance(choice, expected_type):
|
292
293
|
try:
|
293
|
-
|
294
|
+
coerce_value(choice, expected_type)
|
294
295
|
except Exception:
|
295
296
|
raise CommandArgumentError(
|
296
297
|
f"Invalid choice {choice!r}: not coercible to {expected_type.__name__}"
|
@@ -303,7 +304,7 @@ class CommandArgumentParser:
|
|
303
304
|
"""Validate the default value type."""
|
304
305
|
if default is not None and not isinstance(default, expected_type):
|
305
306
|
try:
|
306
|
-
|
307
|
+
coerce_value(default, expected_type)
|
307
308
|
except Exception:
|
308
309
|
raise CommandArgumentError(
|
309
310
|
f"Default value {default!r} for '{dest}' cannot be coerced to {expected_type.__name__}"
|
@@ -316,7 +317,7 @@ class CommandArgumentParser:
|
|
316
317
|
for item in default:
|
317
318
|
if not isinstance(item, expected_type):
|
318
319
|
try:
|
319
|
-
|
320
|
+
coerce_value(item, expected_type)
|
320
321
|
except Exception:
|
321
322
|
raise CommandArgumentError(
|
322
323
|
f"Default list value {default!r} for '{dest}' cannot be coerced to {expected_type.__name__}"
|
@@ -595,7 +596,7 @@ class CommandArgumentParser:
|
|
595
596
|
i += new_i
|
596
597
|
|
597
598
|
try:
|
598
|
-
typed = [spec.type
|
599
|
+
typed = [coerce_value(value, spec.type) for value in values]
|
599
600
|
except Exception:
|
600
601
|
raise CommandArgumentError(
|
601
602
|
f"Invalid value for '{spec.dest}': expected {spec.type.__name__}"
|
@@ -680,7 +681,9 @@ class CommandArgumentParser:
|
|
680
681
|
), "resolver should be an instance of BaseAction"
|
681
682
|
values, new_i = self._consume_nargs(args, i + 1, spec)
|
682
683
|
try:
|
683
|
-
typed_values = [
|
684
|
+
typed_values = [
|
685
|
+
coerce_value(value, spec.type) for value in values
|
686
|
+
]
|
684
687
|
except ValueError:
|
685
688
|
raise CommandArgumentError(
|
686
689
|
f"Invalid value for '{spec.dest}': expected {spec.type.__name__}"
|
@@ -709,7 +712,9 @@ class CommandArgumentParser:
|
|
709
712
|
assert result.get(spec.dest) is not None, "dest should not be None"
|
710
713
|
values, new_i = self._consume_nargs(args, i + 1, spec)
|
711
714
|
try:
|
712
|
-
typed_values = [
|
715
|
+
typed_values = [
|
716
|
+
coerce_value(value, spec.type) for value in values
|
717
|
+
]
|
713
718
|
except ValueError:
|
714
719
|
raise CommandArgumentError(
|
715
720
|
f"Invalid value for '{spec.dest}': expected {spec.type.__name__}"
|
@@ -724,7 +729,9 @@ class CommandArgumentParser:
|
|
724
729
|
assert result.get(spec.dest) is not None, "dest should not be None"
|
725
730
|
values, new_i = self._consume_nargs(args, i + 1, spec)
|
726
731
|
try:
|
727
|
-
typed_values = [
|
732
|
+
typed_values = [
|
733
|
+
coerce_value(value, spec.type) for value in values
|
734
|
+
]
|
728
735
|
except ValueError:
|
729
736
|
raise CommandArgumentError(
|
730
737
|
f"Invalid value for '{spec.dest}': expected {spec.type.__name__}"
|
@@ -735,7 +742,9 @@ class CommandArgumentParser:
|
|
735
742
|
else:
|
736
743
|
values, new_i = self._consume_nargs(args, i + 1, spec)
|
737
744
|
try:
|
738
|
-
typed_values = [
|
745
|
+
typed_values = [
|
746
|
+
coerce_value(value, spec.type) for value in values
|
747
|
+
]
|
739
748
|
except ValueError:
|
740
749
|
raise CommandArgumentError(
|
741
750
|
f"Invalid value for '{spec.dest}': expected {spec.type.__name__}"
|
falyx/parsers/parsers.py
CHANGED
@@ -255,6 +255,10 @@ def get_arg_parsers(
|
|
255
255
|
"list", help="List all available commands with tags"
|
256
256
|
)
|
257
257
|
|
258
|
+
list_parser.add_argument(
|
259
|
+
"-t", "--tag", help="Filter commands by tag (case-insensitive)", default=None
|
260
|
+
)
|
261
|
+
|
258
262
|
version_parser = subparsers.add_parser("version", help="Show the Falyx version")
|
259
263
|
|
260
264
|
return FalyxParsers(
|
falyx/parsers/signature.py
CHANGED
@@ -24,7 +24,6 @@ def infer_args_from_func(
|
|
24
24
|
metadata = (
|
25
25
|
{"help": raw_metadata} if isinstance(raw_metadata, str) else raw_metadata
|
26
26
|
)
|
27
|
-
|
28
27
|
if param.kind not in (
|
29
28
|
inspect.Parameter.POSITIONAL_ONLY,
|
30
29
|
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
@@ -35,6 +34,8 @@ def infer_args_from_func(
|
|
35
34
|
arg_type = (
|
36
35
|
param.annotation if param.annotation is not inspect.Parameter.empty else str
|
37
36
|
)
|
37
|
+
if isinstance(arg_type, str):
|
38
|
+
arg_type = str
|
38
39
|
default = param.default if param.default is not inspect.Parameter.empty else None
|
39
40
|
is_required = param.default is inspect.Parameter.empty
|
40
41
|
if is_required:
|
falyx/parsers/utils.py
CHANGED
@@ -1,10 +1,79 @@
|
|
1
|
-
|
1
|
+
import types
|
2
|
+
from datetime import datetime
|
3
|
+
from enum import EnumMeta
|
4
|
+
from typing import Any, Literal, Union, get_args, get_origin
|
5
|
+
|
6
|
+
from dateutil import parser as date_parser
|
2
7
|
|
3
8
|
from falyx.action.base import BaseAction
|
4
9
|
from falyx.logger import logger
|
5
10
|
from falyx.parsers.signature import infer_args_from_func
|
6
11
|
|
7
12
|
|
13
|
+
def coerce_bool(value: str) -> bool:
|
14
|
+
if isinstance(value, bool):
|
15
|
+
return value
|
16
|
+
value = value.strip().lower()
|
17
|
+
if value in {"true", "1", "yes", "on"}:
|
18
|
+
return True
|
19
|
+
elif value in {"false", "0", "no", "off"}:
|
20
|
+
return False
|
21
|
+
return bool(value)
|
22
|
+
|
23
|
+
|
24
|
+
def coerce_enum(value: Any, enum_type: EnumMeta) -> Any:
|
25
|
+
if isinstance(value, enum_type):
|
26
|
+
return value
|
27
|
+
|
28
|
+
if isinstance(value, str):
|
29
|
+
try:
|
30
|
+
return enum_type[value]
|
31
|
+
except KeyError:
|
32
|
+
pass
|
33
|
+
|
34
|
+
base_type = type(next(iter(enum_type)).value)
|
35
|
+
print(base_type)
|
36
|
+
try:
|
37
|
+
coerced_value = base_type(value)
|
38
|
+
return enum_type(coerced_value)
|
39
|
+
except (ValueError, TypeError):
|
40
|
+
raise ValueError(f"Value '{value}' could not be coerced to enum type {enum_type}")
|
41
|
+
|
42
|
+
|
43
|
+
def coerce_value(value: str, target_type: type) -> Any:
|
44
|
+
origin = get_origin(target_type)
|
45
|
+
args = get_args(target_type)
|
46
|
+
|
47
|
+
if origin is Literal:
|
48
|
+
if value not in args:
|
49
|
+
raise ValueError(
|
50
|
+
f"Value '{value}' is not a valid literal for type {target_type}"
|
51
|
+
)
|
52
|
+
return value
|
53
|
+
|
54
|
+
if isinstance(target_type, types.UnionType) or get_origin(target_type) is Union:
|
55
|
+
for arg in args:
|
56
|
+
try:
|
57
|
+
return coerce_value(value, arg)
|
58
|
+
except Exception:
|
59
|
+
continue
|
60
|
+
raise ValueError(f"Value '{value}' could not be coerced to any of {args!r}")
|
61
|
+
|
62
|
+
if isinstance(target_type, EnumMeta):
|
63
|
+
return coerce_enum(value, target_type)
|
64
|
+
|
65
|
+
if target_type is bool:
|
66
|
+
return coerce_bool(value)
|
67
|
+
|
68
|
+
if target_type is datetime:
|
69
|
+
try:
|
70
|
+
return date_parser.parse(value)
|
71
|
+
except ValueError as e:
|
72
|
+
raise ValueError(f"Value '{value}' could not be parsed as a datetime") from e
|
73
|
+
|
74
|
+
return target_type(value)
|
75
|
+
|
76
|
+
|
8
77
|
def same_argument_definitions(
|
9
78
|
actions: list[Any],
|
10
79
|
arg_metadata: dict[str, str | dict[str, Any]] | None = None,
|
falyx/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.45"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: falyx
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.45
|
4
4
|
Summary: Reliable and introspectable async CLI action framework.
|
5
5
|
License: MIT
|
6
6
|
Author: Roland Thomas Jr
|
@@ -15,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
15
15
|
Requires-Dist: aiohttp (>=3.11,<4.0)
|
16
16
|
Requires-Dist: prompt_toolkit (>=3.0,<4.0)
|
17
17
|
Requires-Dist: pydantic (>=2.0,<3.0)
|
18
|
+
Requires-Dist: python-dateutil (>=2.8,<3.0)
|
18
19
|
Requires-Dist: python-json-logger (>=3.3.0,<4.0.0)
|
19
20
|
Requires-Dist: pyyaml (>=6.0,<7.0)
|
20
21
|
Requires-Dist: rich (>=13.0,<14.0)
|
@@ -23,13 +23,13 @@ falyx/action/signal_action.py,sha256=5UMqvzy7fBnLANGwYUWoe1VRhrr7e-yOVeLdOnCBiJo
|
|
23
23
|
falyx/action/types.py,sha256=NfZz1ufZuvCgp-he2JIItbnjX7LjOUadjtKbjpRlSIY,1399
|
24
24
|
falyx/action/user_input_action.py,sha256=7kL5G7L0j2LuLvHu-CMwOaHyEisagE7O_2G2EhqWRr8,3483
|
25
25
|
falyx/bottom_bar.py,sha256=iWxgOKWgn5YmREeZBuGA50FzqzEfz1-Vnqm0V_fhldc,7383
|
26
|
-
falyx/command.py,sha256=
|
27
|
-
falyx/config.py,sha256=
|
26
|
+
falyx/command.py,sha256=ZILV-cUDBvz9nozVBizfuRERPQATF7wesGXl7RFlJqE,16420
|
27
|
+
falyx/config.py,sha256=ENaODVyGp870qNELjhaegyyrzP8xqahRWABZ2B6Y03g,9703
|
28
28
|
falyx/context.py,sha256=NfBpxzFzn-dYP6I3wrtGFucqm__UZo4SSBLmM8yYayE,10330
|
29
29
|
falyx/debug.py,sha256=IRpYtdH8yeXJEsfP5rASALmBQb2U_EwrTudF2GIDdZY,1545
|
30
30
|
falyx/exceptions.py,sha256=kK9k1v7LVNjJSwYztRa9Krhr3ZOI-6Htq2ZjlYICPKg,922
|
31
31
|
falyx/execution_registry.py,sha256=rctsz0mrIHPToLZqylblVjDdKWdq1x_JBc8GwMP5sJ8,4710
|
32
|
-
falyx/falyx.py,sha256=
|
32
|
+
falyx/falyx.py,sha256=_Aj7UxyFl8KAwZVuQW2aUuHQnHuXWBi6nKh2hsCxYis,47749
|
33
33
|
falyx/hook_manager.py,sha256=TFuHQnAncS_rk6vuw-VSx8bnAppLuHfrZCrzLwqcO9o,2979
|
34
34
|
falyx/hooks.py,sha256=xMfQROib0BNsaQF4AXJpmCiGePoE1f1xpcdibgnVZWM,2913
|
35
35
|
falyx/init.py,sha256=VZ3rYMxo7g01EraYATdl_pRN4ZqrsVueo2ZFx54gojo,3326
|
@@ -38,10 +38,10 @@ falyx/menu.py,sha256=E580qZsx08bnWcqRVjJuD2Fy8Zh_1zIexp5f0lC7L2c,3745
|
|
38
38
|
falyx/options_manager.py,sha256=dFAnQw543tQ6Xupvh1PwBrhiSWlSACHw8K-sHP_lUh4,2842
|
39
39
|
falyx/parsers/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
40
|
falyx/parsers/__init__.py,sha256=ZfPmbtEUechDvgl99-lWhTXmFnXS_FMXJ_xb8KGEJLo,448
|
41
|
-
falyx/parsers/argparse.py,sha256=
|
42
|
-
falyx/parsers/parsers.py,sha256=
|
43
|
-
falyx/parsers/signature.py,sha256=
|
44
|
-
falyx/parsers/utils.py,sha256=
|
41
|
+
falyx/parsers/argparse.py,sha256=7JwGVwrfx5l0rWOOvtc-WHGiEH1nQ3g-sxG9A65q4tg,37313
|
42
|
+
falyx/parsers/parsers.py,sha256=MXWC8OQ3apDaeKfY0O4J8NnkxofWVOCRnKatC00lGm0,8796
|
43
|
+
falyx/parsers/signature.py,sha256=PfDe432PYcJDhDXguNzumFqWjDLk13s6jhZF33r__AM,2326
|
44
|
+
falyx/parsers/utils.py,sha256=w_UzvvP62EDKXWSf3jslEsJfd45usGyFqXKNziQhLRI,2893
|
45
45
|
falyx/prompt_utils.py,sha256=qgk0bXs7mwzflqzWyFhEOTpKQ_ZtMIqGhKeg-ocwNnE,1542
|
46
46
|
falyx/protocols.py,sha256=-9GbCBUzzsEgw2_KOCYqxxzWJuez0eHmwnZp_ShY0jc,493
|
47
47
|
falyx/retry.py,sha256=sGRE9QhdZK98M99G8F15WUsJ_fYLNyLlCgu3UANaSQs,3744
|
@@ -53,9 +53,9 @@ falyx/themes/__init__.py,sha256=1CZhEUCin9cUk8IGYBUFkVvdHRNNJBEFXccHwpUKZCA,284
|
|
53
53
|
falyx/themes/colors.py,sha256=4aaeAHJetmeNInI0Zytg4E3YqKfPFelpf04vtjSvsS8,19776
|
54
54
|
falyx/utils.py,sha256=U45xnZFUdoFC4xiji_9S1jHS5V7MvxSDtufP8EgB0SM,6732
|
55
55
|
falyx/validators.py,sha256=t5iyzVpY8tdC4rfhr4isEfWpD5gNTzjeX_Hbi_Uq6sA,1328
|
56
|
-
falyx/version.py,sha256=
|
57
|
-
falyx-0.1.
|
58
|
-
falyx-0.1.
|
59
|
-
falyx-0.1.
|
60
|
-
falyx-0.1.
|
61
|
-
falyx-0.1.
|
56
|
+
falyx/version.py,sha256=G1Bw5SEeRoSlHVxmFKf6PIpK38SHTYTFhSFGm9d8YQM,23
|
57
|
+
falyx-0.1.45.dist-info/LICENSE,sha256=B0yqgaHuSdhN7T3OBmgQSiDTy8HqT5Oe_dLypRe4Ra4,1073
|
58
|
+
falyx-0.1.45.dist-info/METADATA,sha256=f0xryZQMB6pu-oM5OPOLBnzPWmV9lD4UZch2iJw7CzM,5561
|
59
|
+
falyx-0.1.45.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
60
|
+
falyx-0.1.45.dist-info/entry_points.txt,sha256=j8owOSl2j1Ss8DtGMnKfgehKaolqnIPhVFHaUBLUnMs,45
|
61
|
+
falyx-0.1.45.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|