falyx 0.1.51__py3-none-any.whl → 0.1.52__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/action/__init__.py +2 -1
- falyx/action/action_group.py +2 -0
- falyx/action/chained_action.py +2 -0
- falyx/action/fallback_action.py +2 -0
- falyx/action/io_action.py +0 -93
- falyx/action/literal_input_action.py +2 -0
- falyx/action/mixins.py +2 -0
- falyx/action/process_action.py +2 -0
- falyx/action/process_pool_action.py +2 -0
- falyx/action/shell_action.py +105 -0
- falyx/action/types.py +2 -0
- falyx/action/user_input_action.py +2 -0
- falyx/command.py +1 -1
- falyx/parser/__init__.py +3 -1
- falyx/parser/argument.py +98 -0
- falyx/parser/argument_action.py +27 -0
- falyx/parser/{argparse.py → command_argument_parser.py} +3 -115
- falyx/parser/signature.py +1 -0
- falyx/parser/utils.py +1 -0
- falyx/version.py +1 -1
- {falyx-0.1.51.dist-info → falyx-0.1.52.dist-info}/METADATA +1 -1
- {falyx-0.1.51.dist-info → falyx-0.1.52.dist-info}/RECORD +25 -22
- {falyx-0.1.51.dist-info → falyx-0.1.52.dist-info}/LICENSE +0 -0
- {falyx-0.1.51.dist-info → falyx-0.1.52.dist-info}/WHEEL +0 -0
- {falyx-0.1.51.dist-info → falyx-0.1.52.dist-info}/entry_points.txt +0 -0
falyx/action/__init__.py
CHANGED
@@ -12,7 +12,7 @@ from .base import BaseAction
|
|
12
12
|
from .chained_action import ChainedAction
|
13
13
|
from .fallback_action import FallbackAction
|
14
14
|
from .http_action import HTTPAction
|
15
|
-
from .io_action import BaseIOAction
|
15
|
+
from .io_action import BaseIOAction
|
16
16
|
from .literal_input_action import LiteralInputAction
|
17
17
|
from .menu_action import MenuAction
|
18
18
|
from .process_action import ProcessAction
|
@@ -20,6 +20,7 @@ from .process_pool_action import ProcessPoolAction
|
|
20
20
|
from .prompt_menu_action import PromptMenuAction
|
21
21
|
from .select_file_action import SelectFileAction
|
22
22
|
from .selection_action import SelectionAction
|
23
|
+
from .shell_action import ShellAction
|
23
24
|
from .signal_action import SignalAction
|
24
25
|
from .user_input_action import UserInputAction
|
25
26
|
|
falyx/action/action_group.py
CHANGED
falyx/action/chained_action.py
CHANGED
falyx/action/fallback_action.py
CHANGED
falyx/action/io_action.py
CHANGED
@@ -16,8 +16,6 @@ Common usage includes shell-like filters, input transformers, or any tool that
|
|
16
16
|
needs to consume input from another process or pipeline.
|
17
17
|
"""
|
18
18
|
import asyncio
|
19
|
-
import shlex
|
20
|
-
import subprocess
|
21
19
|
import sys
|
22
20
|
from typing import Any, Callable
|
23
21
|
|
@@ -25,10 +23,8 @@ from rich.tree import Tree
|
|
25
23
|
|
26
24
|
from falyx.action.base import BaseAction
|
27
25
|
from falyx.context import ExecutionContext
|
28
|
-
from falyx.exceptions import FalyxError
|
29
26
|
from falyx.execution_registry import ExecutionRegistry as er
|
30
27
|
from falyx.hook_manager import HookManager, HookType
|
31
|
-
from falyx.logger import logger
|
32
28
|
from falyx.themes import OneColors
|
33
29
|
|
34
30
|
|
@@ -171,92 +167,3 @@ class BaseIOAction(BaseAction):
|
|
171
167
|
parent.add("".join(label))
|
172
168
|
else:
|
173
169
|
self.console.print(Tree("".join(label)))
|
174
|
-
|
175
|
-
|
176
|
-
class ShellAction(BaseIOAction):
|
177
|
-
"""
|
178
|
-
ShellAction wraps a shell command template for CLI pipelines.
|
179
|
-
|
180
|
-
This Action takes parsed input (from stdin, literal, or last_result),
|
181
|
-
substitutes it into the provided shell command template, and executes
|
182
|
-
the command asynchronously using subprocess.
|
183
|
-
|
184
|
-
Designed for quick integration with shell tools like `grep`, `ping`, `jq`, etc.
|
185
|
-
|
186
|
-
⚠️ Security Warning:
|
187
|
-
By default, ShellAction uses `shell=True`, which can be dangerous with
|
188
|
-
unsanitized input. To mitigate this, set `safe_mode=True` to use `shell=False`
|
189
|
-
with `shlex.split()`.
|
190
|
-
|
191
|
-
Features:
|
192
|
-
- Automatically handles input parsing (str/bytes)
|
193
|
-
- `safe_mode=True` disables shell interpretation and runs with `shell=False`
|
194
|
-
- Captures stdout and stderr from shell execution
|
195
|
-
- Raises on non-zero exit codes with stderr as the error
|
196
|
-
- Result is returned as trimmed stdout string
|
197
|
-
|
198
|
-
Args:
|
199
|
-
name (str): Name of the action.
|
200
|
-
command_template (str): Shell command to execute. Must include `{}` to include
|
201
|
-
input. If no placeholder is present, the input is not
|
202
|
-
included.
|
203
|
-
safe_mode (bool): If True, runs with `shell=False` using shlex parsing
|
204
|
-
(default: False).
|
205
|
-
"""
|
206
|
-
|
207
|
-
def __init__(
|
208
|
-
self, name: str, command_template: str, safe_mode: bool = False, **kwargs
|
209
|
-
):
|
210
|
-
super().__init__(name=name, **kwargs)
|
211
|
-
self.command_template = command_template
|
212
|
-
self.safe_mode = safe_mode
|
213
|
-
|
214
|
-
def from_input(self, raw: str | bytes) -> str:
|
215
|
-
if not isinstance(raw, (str, bytes)):
|
216
|
-
raise TypeError(
|
217
|
-
f"{self.name} expected str or bytes input, got {type(raw).__name__}"
|
218
|
-
)
|
219
|
-
return raw.strip() if isinstance(raw, str) else raw.decode("utf-8").strip()
|
220
|
-
|
221
|
-
def get_infer_target(self) -> tuple[Callable[..., Any] | None, dict[str, Any] | None]:
|
222
|
-
if sys.stdin.isatty():
|
223
|
-
return self._run, {"parsed_input": {"help": self.command_template}}
|
224
|
-
return None, None
|
225
|
-
|
226
|
-
async def _run(self, parsed_input: str) -> str:
|
227
|
-
# Replace placeholder in template, or use raw input as full command
|
228
|
-
command = self.command_template.format(parsed_input)
|
229
|
-
if self.safe_mode:
|
230
|
-
try:
|
231
|
-
args = shlex.split(command)
|
232
|
-
except ValueError as error:
|
233
|
-
raise FalyxError(f"Invalid command template: {error}")
|
234
|
-
result = subprocess.run(args, capture_output=True, text=True, check=True)
|
235
|
-
else:
|
236
|
-
result = subprocess.run(
|
237
|
-
command, shell=True, text=True, capture_output=True, check=True
|
238
|
-
)
|
239
|
-
if result.returncode != 0:
|
240
|
-
raise RuntimeError(result.stderr.strip())
|
241
|
-
return result.stdout.strip()
|
242
|
-
|
243
|
-
def to_output(self, result: str) -> str:
|
244
|
-
return result
|
245
|
-
|
246
|
-
async def preview(self, parent: Tree | None = None):
|
247
|
-
label = [f"[{OneColors.GREEN_b}]⚙ ShellAction[/] '{self.name}'"]
|
248
|
-
label.append(f"\n[dim]Template:[/] {self.command_template}")
|
249
|
-
label.append(
|
250
|
-
f"\n[dim]Safe mode:[/] {'Enabled' if self.safe_mode else 'Disabled'}"
|
251
|
-
)
|
252
|
-
if self.inject_last_result:
|
253
|
-
label.append(f" [dim](injects '{self.inject_into}')[/dim]")
|
254
|
-
tree = parent.add("".join(label)) if parent else Tree("".join(label))
|
255
|
-
if not parent:
|
256
|
-
self.console.print(tree)
|
257
|
-
|
258
|
-
def __str__(self):
|
259
|
-
return (
|
260
|
-
f"ShellAction(name={self.name!r}, command_template={self.command_template!r},"
|
261
|
-
f" safe_mode={self.safe_mode})"
|
262
|
-
)
|
falyx/action/mixins.py
CHANGED
falyx/action/process_action.py
CHANGED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
|
2
|
+
"""shell_action.py
|
3
|
+
Execute shell commands with input substitution."""
|
4
|
+
|
5
|
+
from __future__ import annotations
|
6
|
+
|
7
|
+
import shlex
|
8
|
+
import subprocess
|
9
|
+
import sys
|
10
|
+
from typing import Any, Callable
|
11
|
+
|
12
|
+
from rich.tree import Tree
|
13
|
+
|
14
|
+
from falyx.action.io_action import BaseIOAction
|
15
|
+
from falyx.exceptions import FalyxError
|
16
|
+
from falyx.themes import OneColors
|
17
|
+
|
18
|
+
|
19
|
+
class ShellAction(BaseIOAction):
|
20
|
+
"""
|
21
|
+
ShellAction wraps a shell command template for CLI pipelines.
|
22
|
+
|
23
|
+
This Action takes parsed input (from stdin, literal, or last_result),
|
24
|
+
substitutes it into the provided shell command template, and executes
|
25
|
+
the command asynchronously using subprocess.
|
26
|
+
|
27
|
+
Designed for quick integration with shell tools like `grep`, `ping`, `jq`, etc.
|
28
|
+
|
29
|
+
⚠️ Security Warning:
|
30
|
+
By default, ShellAction uses `shell=True`, which can be dangerous with
|
31
|
+
unsanitized input. To mitigate this, set `safe_mode=True` to use `shell=False`
|
32
|
+
with `shlex.split()`.
|
33
|
+
|
34
|
+
Features:
|
35
|
+
- Automatically handles input parsing (str/bytes)
|
36
|
+
- `safe_mode=True` disables shell interpretation and runs with `shell=False`
|
37
|
+
- Captures stdout and stderr from shell execution
|
38
|
+
- Raises on non-zero exit codes with stderr as the error
|
39
|
+
- Result is returned as trimmed stdout string
|
40
|
+
|
41
|
+
Args:
|
42
|
+
name (str): Name of the action.
|
43
|
+
command_template (str): Shell command to execute. Must include `{}` to include
|
44
|
+
input. If no placeholder is present, the input is not
|
45
|
+
included.
|
46
|
+
safe_mode (bool): If True, runs with `shell=False` using shlex parsing
|
47
|
+
(default: False).
|
48
|
+
"""
|
49
|
+
|
50
|
+
def __init__(
|
51
|
+
self, name: str, command_template: str, safe_mode: bool = False, **kwargs
|
52
|
+
):
|
53
|
+
super().__init__(name=name, **kwargs)
|
54
|
+
self.command_template = command_template
|
55
|
+
self.safe_mode = safe_mode
|
56
|
+
|
57
|
+
def from_input(self, raw: str | bytes) -> str:
|
58
|
+
if not isinstance(raw, (str, bytes)):
|
59
|
+
raise TypeError(
|
60
|
+
f"{self.name} expected str or bytes input, got {type(raw).__name__}"
|
61
|
+
)
|
62
|
+
return raw.strip() if isinstance(raw, str) else raw.decode("utf-8").strip()
|
63
|
+
|
64
|
+
def get_infer_target(self) -> tuple[Callable[..., Any] | None, dict[str, Any] | None]:
|
65
|
+
if sys.stdin.isatty():
|
66
|
+
return self._run, {"parsed_input": {"help": self.command_template}}
|
67
|
+
return None, None
|
68
|
+
|
69
|
+
async def _run(self, parsed_input: str) -> str:
|
70
|
+
# Replace placeholder in template, or use raw input as full command
|
71
|
+
command = self.command_template.format(parsed_input)
|
72
|
+
if self.safe_mode:
|
73
|
+
try:
|
74
|
+
args = shlex.split(command)
|
75
|
+
except ValueError as error:
|
76
|
+
raise FalyxError(f"Invalid command template: {error}")
|
77
|
+
result = subprocess.run(args, capture_output=True, text=True, check=True)
|
78
|
+
else:
|
79
|
+
result = subprocess.run(
|
80
|
+
command, shell=True, text=True, capture_output=True, check=True
|
81
|
+
)
|
82
|
+
if result.returncode != 0:
|
83
|
+
raise RuntimeError(result.stderr.strip())
|
84
|
+
return result.stdout.strip()
|
85
|
+
|
86
|
+
def to_output(self, result: str) -> str:
|
87
|
+
return result
|
88
|
+
|
89
|
+
async def preview(self, parent: Tree | None = None):
|
90
|
+
label = [f"[{OneColors.GREEN_b}]⚙ ShellAction[/] '{self.name}'"]
|
91
|
+
label.append(f"\n[dim]Template:[/] {self.command_template}")
|
92
|
+
label.append(
|
93
|
+
f"\n[dim]Safe mode:[/] {'Enabled' if self.safe_mode else 'Disabled'}"
|
94
|
+
)
|
95
|
+
if self.inject_last_result:
|
96
|
+
label.append(f" [dim](injects '{self.inject_into}')[/dim]")
|
97
|
+
tree = parent.add("".join(label)) if parent else Tree("".join(label))
|
98
|
+
if not parent:
|
99
|
+
self.console.print(tree)
|
100
|
+
|
101
|
+
def __str__(self):
|
102
|
+
return (
|
103
|
+
f"ShellAction(name={self.name!r}, command_template={self.command_template!r},"
|
104
|
+
f" safe_mode={self.safe_mode})"
|
105
|
+
)
|
falyx/action/types.py
CHANGED
falyx/command.py
CHANGED
@@ -34,7 +34,7 @@ from falyx.execution_registry import ExecutionRegistry as er
|
|
34
34
|
from falyx.hook_manager import HookManager, HookType
|
35
35
|
from falyx.logger import logger
|
36
36
|
from falyx.options_manager import OptionsManager
|
37
|
-
from falyx.parser.
|
37
|
+
from falyx.parser.command_argument_parser import CommandArgumentParser
|
38
38
|
from falyx.parser.signature import infer_args_from_func
|
39
39
|
from falyx.prompt_utils import confirm_async, should_prompt_user
|
40
40
|
from falyx.protocols import ArgParserProtocol
|
falyx/parser/__init__.py
CHANGED
@@ -5,7 +5,9 @@ Copyright (c) 2025 rtj.dev LLC.
|
|
5
5
|
Licensed under the MIT License. See LICENSE file for details.
|
6
6
|
"""
|
7
7
|
|
8
|
-
from .
|
8
|
+
from .argument import Argument
|
9
|
+
from .argument_action import ArgumentAction
|
10
|
+
from .command_argument_parser import CommandArgumentParser
|
9
11
|
from .parsers import FalyxParsers, get_arg_parsers, get_root_parser, get_subparsers
|
10
12
|
|
11
13
|
__all__ = [
|
falyx/parser/argument.py
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
|
2
|
+
"""argument.py"""
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import Any
|
5
|
+
|
6
|
+
from falyx.action.base import BaseAction
|
7
|
+
from falyx.parser.argument_action import ArgumentAction
|
8
|
+
|
9
|
+
|
10
|
+
@dataclass
|
11
|
+
class Argument:
|
12
|
+
"""Represents a command-line argument."""
|
13
|
+
|
14
|
+
flags: tuple[str, ...]
|
15
|
+
dest: str # Destination name for the argument
|
16
|
+
action: ArgumentAction = (
|
17
|
+
ArgumentAction.STORE
|
18
|
+
) # Action to be taken when the argument is encountered
|
19
|
+
type: Any = str # Type of the argument (e.g., str, int, float) or callable
|
20
|
+
default: Any = None # Default value if the argument is not provided
|
21
|
+
choices: list[str] | None = None # List of valid choices for the argument
|
22
|
+
required: bool = False # True if the argument is required
|
23
|
+
help: str = "" # Help text for the argument
|
24
|
+
nargs: int | str | None = None # int, '?', '*', '+', None
|
25
|
+
positional: bool = False # True if no leading - or -- in flags
|
26
|
+
resolver: BaseAction | None = None # Action object for the argument
|
27
|
+
|
28
|
+
def get_positional_text(self) -> str:
|
29
|
+
"""Get the positional text for the argument."""
|
30
|
+
text = ""
|
31
|
+
if self.positional:
|
32
|
+
if self.choices:
|
33
|
+
text = f"{{{','.join([str(choice) for choice in self.choices])}}}"
|
34
|
+
else:
|
35
|
+
text = self.dest
|
36
|
+
return text
|
37
|
+
|
38
|
+
def get_choice_text(self) -> str:
|
39
|
+
"""Get the choice text for the argument."""
|
40
|
+
choice_text = ""
|
41
|
+
if self.choices:
|
42
|
+
choice_text = f"{{{','.join([str(choice) for choice in self.choices])}}}"
|
43
|
+
elif (
|
44
|
+
self.action
|
45
|
+
in (
|
46
|
+
ArgumentAction.STORE,
|
47
|
+
ArgumentAction.APPEND,
|
48
|
+
ArgumentAction.EXTEND,
|
49
|
+
)
|
50
|
+
and not self.positional
|
51
|
+
):
|
52
|
+
choice_text = self.dest.upper()
|
53
|
+
elif self.action in (
|
54
|
+
ArgumentAction.STORE,
|
55
|
+
ArgumentAction.APPEND,
|
56
|
+
ArgumentAction.EXTEND,
|
57
|
+
) or isinstance(self.nargs, str):
|
58
|
+
choice_text = self.dest
|
59
|
+
|
60
|
+
if self.nargs == "?":
|
61
|
+
choice_text = f"[{choice_text}]"
|
62
|
+
elif self.nargs == "*":
|
63
|
+
choice_text = f"[{choice_text} ...]"
|
64
|
+
elif self.nargs == "+":
|
65
|
+
choice_text = f"{choice_text} [{choice_text} ...]"
|
66
|
+
return choice_text
|
67
|
+
|
68
|
+
def __eq__(self, other: object) -> bool:
|
69
|
+
if not isinstance(other, Argument):
|
70
|
+
return False
|
71
|
+
return (
|
72
|
+
self.flags == other.flags
|
73
|
+
and self.dest == other.dest
|
74
|
+
and self.action == other.action
|
75
|
+
and self.type == other.type
|
76
|
+
and self.choices == other.choices
|
77
|
+
and self.required == other.required
|
78
|
+
and self.nargs == other.nargs
|
79
|
+
and self.positional == other.positional
|
80
|
+
and self.default == other.default
|
81
|
+
and self.help == other.help
|
82
|
+
)
|
83
|
+
|
84
|
+
def __hash__(self) -> int:
|
85
|
+
return hash(
|
86
|
+
(
|
87
|
+
tuple(self.flags),
|
88
|
+
self.dest,
|
89
|
+
self.action,
|
90
|
+
self.type,
|
91
|
+
tuple(self.choices or []),
|
92
|
+
self.required,
|
93
|
+
self.nargs,
|
94
|
+
self.positional,
|
95
|
+
self.default,
|
96
|
+
self.help,
|
97
|
+
)
|
98
|
+
)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
|
2
|
+
"""argument_action.py"""
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from enum import Enum
|
6
|
+
|
7
|
+
|
8
|
+
class ArgumentAction(Enum):
|
9
|
+
"""Defines the action to be taken when the argument is encountered."""
|
10
|
+
|
11
|
+
ACTION = "action"
|
12
|
+
STORE = "store"
|
13
|
+
STORE_TRUE = "store_true"
|
14
|
+
STORE_FALSE = "store_false"
|
15
|
+
APPEND = "append"
|
16
|
+
EXTEND = "extend"
|
17
|
+
COUNT = "count"
|
18
|
+
HELP = "help"
|
19
|
+
|
20
|
+
@classmethod
|
21
|
+
def choices(cls) -> list[ArgumentAction]:
|
22
|
+
"""Return a list of all argument actions."""
|
23
|
+
return list(cls)
|
24
|
+
|
25
|
+
def __str__(self) -> str:
|
26
|
+
"""Return the string representation of the argument action."""
|
27
|
+
return self.value
|
@@ -1,9 +1,8 @@
|
|
1
1
|
# Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
|
2
|
+
"""command_argument_parser.py"""
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
from copy import deepcopy
|
5
|
-
from dataclasses import dataclass
|
6
|
-
from enum import Enum
|
7
6
|
from typing import Any, Iterable
|
8
7
|
|
9
8
|
from rich.console import Console
|
@@ -12,123 +11,12 @@ from rich.text import Text
|
|
12
11
|
|
13
12
|
from falyx.action.base import BaseAction
|
14
13
|
from falyx.exceptions import CommandArgumentError
|
14
|
+
from falyx.parser.argument import Argument
|
15
|
+
from falyx.parser.argument_action import ArgumentAction
|
15
16
|
from falyx.parser.utils import coerce_value
|
16
17
|
from falyx.signals import HelpSignal
|
17
18
|
|
18
19
|
|
19
|
-
class ArgumentAction(Enum):
|
20
|
-
"""Defines the action to be taken when the argument is encountered."""
|
21
|
-
|
22
|
-
ACTION = "action"
|
23
|
-
STORE = "store"
|
24
|
-
STORE_TRUE = "store_true"
|
25
|
-
STORE_FALSE = "store_false"
|
26
|
-
APPEND = "append"
|
27
|
-
EXTEND = "extend"
|
28
|
-
COUNT = "count"
|
29
|
-
HELP = "help"
|
30
|
-
|
31
|
-
@classmethod
|
32
|
-
def choices(cls) -> list[ArgumentAction]:
|
33
|
-
"""Return a list of all argument actions."""
|
34
|
-
return list(cls)
|
35
|
-
|
36
|
-
def __str__(self) -> str:
|
37
|
-
"""Return the string representation of the argument action."""
|
38
|
-
return self.value
|
39
|
-
|
40
|
-
|
41
|
-
@dataclass
|
42
|
-
class Argument:
|
43
|
-
"""Represents a command-line argument."""
|
44
|
-
|
45
|
-
flags: tuple[str, ...]
|
46
|
-
dest: str # Destination name for the argument
|
47
|
-
action: ArgumentAction = (
|
48
|
-
ArgumentAction.STORE
|
49
|
-
) # Action to be taken when the argument is encountered
|
50
|
-
type: Any = str # Type of the argument (e.g., str, int, float) or callable
|
51
|
-
default: Any = None # Default value if the argument is not provided
|
52
|
-
choices: list[str] | None = None # List of valid choices for the argument
|
53
|
-
required: bool = False # True if the argument is required
|
54
|
-
help: str = "" # Help text for the argument
|
55
|
-
nargs: int | str | None = None # int, '?', '*', '+', None
|
56
|
-
positional: bool = False # True if no leading - or -- in flags
|
57
|
-
resolver: BaseAction | None = None # Action object for the argument
|
58
|
-
|
59
|
-
def get_positional_text(self) -> str:
|
60
|
-
"""Get the positional text for the argument."""
|
61
|
-
text = ""
|
62
|
-
if self.positional:
|
63
|
-
if self.choices:
|
64
|
-
text = f"{{{','.join([str(choice) for choice in self.choices])}}}"
|
65
|
-
else:
|
66
|
-
text = self.dest
|
67
|
-
return text
|
68
|
-
|
69
|
-
def get_choice_text(self) -> str:
|
70
|
-
"""Get the choice text for the argument."""
|
71
|
-
choice_text = ""
|
72
|
-
if self.choices:
|
73
|
-
choice_text = f"{{{','.join([str(choice) for choice in self.choices])}}}"
|
74
|
-
elif (
|
75
|
-
self.action
|
76
|
-
in (
|
77
|
-
ArgumentAction.STORE,
|
78
|
-
ArgumentAction.APPEND,
|
79
|
-
ArgumentAction.EXTEND,
|
80
|
-
)
|
81
|
-
and not self.positional
|
82
|
-
):
|
83
|
-
choice_text = self.dest.upper()
|
84
|
-
elif self.action in (
|
85
|
-
ArgumentAction.STORE,
|
86
|
-
ArgumentAction.APPEND,
|
87
|
-
ArgumentAction.EXTEND,
|
88
|
-
) or isinstance(self.nargs, str):
|
89
|
-
choice_text = self.dest
|
90
|
-
|
91
|
-
if self.nargs == "?":
|
92
|
-
choice_text = f"[{choice_text}]"
|
93
|
-
elif self.nargs == "*":
|
94
|
-
choice_text = f"[{choice_text} ...]"
|
95
|
-
elif self.nargs == "+":
|
96
|
-
choice_text = f"{choice_text} [{choice_text} ...]"
|
97
|
-
return choice_text
|
98
|
-
|
99
|
-
def __eq__(self, other: object) -> bool:
|
100
|
-
if not isinstance(other, Argument):
|
101
|
-
return False
|
102
|
-
return (
|
103
|
-
self.flags == other.flags
|
104
|
-
and self.dest == other.dest
|
105
|
-
and self.action == other.action
|
106
|
-
and self.type == other.type
|
107
|
-
and self.choices == other.choices
|
108
|
-
and self.required == other.required
|
109
|
-
and self.nargs == other.nargs
|
110
|
-
and self.positional == other.positional
|
111
|
-
and self.default == other.default
|
112
|
-
and self.help == other.help
|
113
|
-
)
|
114
|
-
|
115
|
-
def __hash__(self) -> int:
|
116
|
-
return hash(
|
117
|
-
(
|
118
|
-
tuple(self.flags),
|
119
|
-
self.dest,
|
120
|
-
self.action,
|
121
|
-
self.type,
|
122
|
-
tuple(self.choices or []),
|
123
|
-
self.required,
|
124
|
-
self.nargs,
|
125
|
-
self.positional,
|
126
|
-
self.default,
|
127
|
-
self.help,
|
128
|
-
)
|
129
|
-
)
|
130
|
-
|
131
|
-
|
132
20
|
class CommandArgumentParser:
|
133
21
|
"""
|
134
22
|
Custom argument parser for Falyx Commands.
|
falyx/parser/signature.py
CHANGED
falyx/parser/utils.py
CHANGED
falyx/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.52"
|
@@ -2,28 +2,29 @@ falyx/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
falyx/__init__.py,sha256=Gh88lQ5pbD7xbGWrBgslE2kSTZKY9TkvKSa53rZ3l8U,305
|
3
3
|
falyx/__main__.py,sha256=xHO4pB45rccixo-ougF84QJeB36ef8mEZXWVK_CJL9M,3420
|
4
4
|
falyx/action/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
falyx/action/__init__.py,sha256=
|
5
|
+
falyx/action/__init__.py,sha256=xpsZJVtMFP9vtmg6LSS3QjZrezD2ZxGZUBAjv4axuuw,1272
|
6
6
|
falyx/action/action.py,sha256=j9ANO0xRfWoiNK6z-46T04EKAJ7GhjVrzb8_U8afEAA,5753
|
7
7
|
falyx/action/action_factory.py,sha256=br-P7Oip-4tZkO8qVT_ECwLe6idYjJa_GuBi5QR7vS4,4832
|
8
|
-
falyx/action/action_group.py,sha256=
|
8
|
+
falyx/action/action_group.py,sha256=NT2m9aLHUV2CqJxaDTAXFOH5_9F07TaCDmhybrO5dvU,6920
|
9
9
|
falyx/action/base.py,sha256=B7mt66oznmhv2qpSOwOuScgMckVXrxjRMU2buzZkRD8,5866
|
10
|
-
falyx/action/chained_action.py,sha256=
|
11
|
-
falyx/action/fallback_action.py,sha256=
|
10
|
+
falyx/action/chained_action.py,sha256=0qSZBtL8G1Mb4S-iisBjOlsX8GDq8iB6iecf0vvp2L8,8589
|
11
|
+
falyx/action/fallback_action.py,sha256=3FGWfoR1MIgY0ZkDNOpKu8p3JqPWzh5ON3943mfgDGs,1708
|
12
12
|
falyx/action/http_action.py,sha256=DNeSBWh58UTFGlfFyTk2GnhS54hpLAJLC0QNbq2cYic,5799
|
13
|
-
falyx/action/io_action.py,sha256=
|
14
|
-
falyx/action/literal_input_action.py,sha256=
|
13
|
+
falyx/action/io_action.py,sha256=uOehF3ryqSUf0ye4cyQrHyNvf7TMnwfgt2EtZNEeHr0,6121
|
14
|
+
falyx/action/literal_input_action.py,sha256=ShXXiUYKg01BMZRChlxEWlNcaLXV1B1LW-w5A8mOPvA,1387
|
15
15
|
falyx/action/menu_action.py,sha256=SLqwmQ1TOt8kl_cgIWogBYfx8lYPLZa4E-Yy6M2cX_w,6069
|
16
|
-
falyx/action/mixins.py,sha256=
|
17
|
-
falyx/action/process_action.py,sha256=
|
18
|
-
falyx/action/process_pool_action.py,sha256=
|
16
|
+
falyx/action/mixins.py,sha256=xWFyiGAcocTb9yTtHtTiAuuYdIc8vqLPreJAHPA6jBs,1197
|
17
|
+
falyx/action/process_action.py,sha256=UdE6ab5fwS03iRY3Xk6fehpPZ47wo7yQT9tZmWiSTgw,4659
|
18
|
+
falyx/action/process_pool_action.py,sha256=soHrecetIVN-dzgCS4jSdC0cnabDZQGwCWjPPOAFUIs,6032
|
19
19
|
falyx/action/prompt_menu_action.py,sha256=corzjpPNVMYKncfueeRUWwklnlZHN-Fc61psOzbZELg,5286
|
20
20
|
falyx/action/select_file_action.py,sha256=2T4I1CLvHLAAqNUD2rFBIpdi74BP5amU4yTHUOGnd64,9911
|
21
21
|
falyx/action/selection_action.py,sha256=Mav39iTkVIJPDvmDek8R2bSF18f-mII56l5sSzZSPII,15735
|
22
|
+
falyx/action/shell_action.py,sha256=0A_kvZLsYmeLHInMM_4Jpe8GCSnXzGBm7H9PnXPvbAs,4055
|
22
23
|
falyx/action/signal_action.py,sha256=5UMqvzy7fBnLANGwYUWoe1VRhrr7e-yOVeLdOnCBiJo,1350
|
23
|
-
falyx/action/types.py,sha256=
|
24
|
-
falyx/action/user_input_action.py,sha256=
|
24
|
+
falyx/action/types.py,sha256=ml-KMelDjYnXdUTR1n7mHEwZFpAIdtB3RTnJS0KdVCQ,1478
|
25
|
+
falyx/action/user_input_action.py,sha256=ywbuHciMhXfZpLuHFBF8PBcm_bnmH3VLib66RrKFSx0,3841
|
25
26
|
falyx/bottom_bar.py,sha256=KPACb9VC0I3dv_pYZLqy7e4uA_KT5dSfwnvuknyV0FI,7388
|
26
|
-
falyx/command.py,sha256=
|
27
|
+
falyx/command.py,sha256=v6GOVOPDmcjfKq0uR4EYXuqXSAYOVFp9Iy1hlZq4W5w,16432
|
27
28
|
falyx/config.py,sha256=Cm1F9SfNSbugPALxaEz7NRqp1wrk-g2jYq35bQzN2uE,9658
|
28
29
|
falyx/context.py,sha256=b9PGkIfhc1BbFUmaqmr4AojzONfKG1c9WP2uixzCJGQ,10806
|
29
30
|
falyx/debug.py,sha256=pguI0XQcZ-7jte5YUPexAufa1oxxalYO1JgmO6GU3rI,1557
|
@@ -37,11 +38,13 @@ falyx/logger.py,sha256=1Mfb_vJFJ1tQwziuyU2p-cSMi2Js8N2byniFEnI6vOQ,132
|
|
37
38
|
falyx/menu.py,sha256=E580qZsx08bnWcqRVjJuD2Fy8Zh_1zIexp5f0lC7L2c,3745
|
38
39
|
falyx/options_manager.py,sha256=dFAnQw543tQ6Xupvh1PwBrhiSWlSACHw8K-sHP_lUh4,2842
|
39
40
|
falyx/parser/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
|
-
falyx/parser/__init__.py,sha256=
|
41
|
-
falyx/parser/
|
41
|
+
falyx/parser/__init__.py,sha256=NbxAovKIY-duFTs6DAsdM_OzL7s3VIu19KMOmltX9ts,512
|
42
|
+
falyx/parser/argument.py,sha256=5udUzYOgxdOz4thI0bxuRsqGFf_YuId4LP7MZ6n0dYc,3362
|
43
|
+
falyx/parser/argument_action.py,sha256=rNVeth0eMpkZRU_eT1RPVxOGzD4pbdAMx9Kq07T4mG4,709
|
44
|
+
falyx/parser/command_argument_parser.py,sha256=c6mHuOxAWdt5CXMnZv-ZvAf0DDdNhSWaOYu2KIJGAFA,33892
|
42
45
|
falyx/parser/parsers.py,sha256=MXWC8OQ3apDaeKfY0O4J8NnkxofWVOCRnKatC00lGm0,8796
|
43
|
-
falyx/parser/signature.py,sha256=
|
44
|
-
falyx/parser/utils.py,sha256=
|
46
|
+
falyx/parser/signature.py,sha256=fSltLEr8ctj1qpbU-OvTMnREjlb8OTG5t-guJFR7j4E,2529
|
47
|
+
falyx/parser/utils.py,sha256=W3uuvzftwE7Yuiwp_YsrvkIpJp0WcFEIdrRv8SCsnds,2956
|
45
48
|
falyx/prompt_utils.py,sha256=qgk0bXs7mwzflqzWyFhEOTpKQ_ZtMIqGhKeg-ocwNnE,1542
|
46
49
|
falyx/protocols.py,sha256=-9GbCBUzzsEgw2_KOCYqxxzWJuez0eHmwnZp_ShY0jc,493
|
47
50
|
falyx/retry.py,sha256=sGRE9QhdZK98M99G8F15WUsJ_fYLNyLlCgu3UANaSQs,3744
|
@@ -53,9 +56,9 @@ falyx/themes/__init__.py,sha256=1CZhEUCin9cUk8IGYBUFkVvdHRNNJBEFXccHwpUKZCA,284
|
|
53
56
|
falyx/themes/colors.py,sha256=4aaeAHJetmeNInI0Zytg4E3YqKfPFelpf04vtjSvsS8,19776
|
54
57
|
falyx/utils.py,sha256=U45xnZFUdoFC4xiji_9S1jHS5V7MvxSDtufP8EgB0SM,6732
|
55
58
|
falyx/validators.py,sha256=Pbdxh5777Y03HxyArAh2ApeVSx23in4w4K38G43Vt98,5197
|
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.
|
59
|
+
falyx/version.py,sha256=xEFLBJ_IHewFRxpAOMcKAhQVPVf06lsExSa2472N2G8,23
|
60
|
+
falyx-0.1.52.dist-info/LICENSE,sha256=B0yqgaHuSdhN7T3OBmgQSiDTy8HqT5Oe_dLypRe4Ra4,1073
|
61
|
+
falyx-0.1.52.dist-info/METADATA,sha256=KEyMpUA-OEVmqKEHDTXguJV_id4mevnq9TDAAHSIcgM,5561
|
62
|
+
falyx-0.1.52.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
63
|
+
falyx-0.1.52.dist-info/entry_points.txt,sha256=j8owOSl2j1Ss8DtGMnKfgehKaolqnIPhVFHaUBLUnMs,45
|
64
|
+
falyx-0.1.52.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|