falyx 0.1.27__py3-none-any.whl → 0.1.29__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/.pytyped +0 -0
- falyx/action/io_action.py +4 -1
- falyx/command.py +100 -2
- falyx/exceptions.py +4 -0
- falyx/falyx.py +123 -38
- falyx/parsers/.pytyped +0 -0
- falyx/parsers/__init__.py +21 -0
- falyx/parsers/argparse.py +756 -0
- falyx/{parsers.py → parsers/parsers.py} +7 -1
- falyx/parsers/signature.py +71 -0
- falyx/parsers/utils.py +33 -0
- falyx/protocols.py +7 -1
- falyx/signals.py +7 -0
- falyx/version.py +1 -1
- {falyx-0.1.27.dist-info → falyx-0.1.29.dist-info}/METADATA +1 -1
- {falyx-0.1.27.dist-info → falyx-0.1.29.dist-info}/RECORD +19 -14
- falyx/config_schema.py +0 -76
- {falyx-0.1.27.dist-info → falyx-0.1.29.dist-info}/LICENSE +0 -0
- {falyx-0.1.27.dist-info → falyx-0.1.29.dist-info}/WHEEL +0 -0
- {falyx-0.1.27.dist-info → falyx-0.1.29.dist-info}/entry_points.txt +0 -0
@@ -2,7 +2,7 @@
|
|
2
2
|
"""parsers.py
|
3
3
|
This module contains the argument parsers used for the Falyx CLI.
|
4
4
|
"""
|
5
|
-
from argparse import ArgumentParser, Namespace, _SubParsersAction
|
5
|
+
from argparse import REMAINDER, ArgumentParser, Namespace, _SubParsersAction
|
6
6
|
from dataclasses import asdict, dataclass
|
7
7
|
from typing import Any, Sequence
|
8
8
|
|
@@ -114,6 +114,12 @@ def get_arg_parsers(
|
|
114
114
|
help="Skip confirmation prompts",
|
115
115
|
)
|
116
116
|
|
117
|
+
run_group.add_argument(
|
118
|
+
"command_args",
|
119
|
+
nargs=REMAINDER,
|
120
|
+
help="Arguments to pass to the command (if applicable)",
|
121
|
+
)
|
122
|
+
|
117
123
|
run_all_parser = subparsers.add_parser(
|
118
124
|
"run-all", help="Run all commands with a given tag"
|
119
125
|
)
|
@@ -0,0 +1,71 @@
|
|
1
|
+
import inspect
|
2
|
+
from typing import Any, Callable
|
3
|
+
|
4
|
+
from falyx import logger
|
5
|
+
|
6
|
+
|
7
|
+
def infer_args_from_func(
|
8
|
+
func: Callable[[Any], Any],
|
9
|
+
arg_metadata: dict[str, str | dict[str, Any]] | None = None,
|
10
|
+
) -> list[dict[str, Any]]:
|
11
|
+
"""
|
12
|
+
Infer argument definitions from a callable's signature.
|
13
|
+
Returns a list of kwargs suitable for CommandArgumentParser.add_argument.
|
14
|
+
"""
|
15
|
+
arg_metadata = arg_metadata or {}
|
16
|
+
signature = inspect.signature(func)
|
17
|
+
arg_defs = []
|
18
|
+
|
19
|
+
for name, param in signature.parameters.items():
|
20
|
+
raw_metadata = arg_metadata.get(name, {})
|
21
|
+
metadata = (
|
22
|
+
{"help": raw_metadata} if isinstance(raw_metadata, str) else raw_metadata
|
23
|
+
)
|
24
|
+
|
25
|
+
if param.kind not in (
|
26
|
+
inspect.Parameter.POSITIONAL_ONLY,
|
27
|
+
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
28
|
+
inspect.Parameter.KEYWORD_ONLY,
|
29
|
+
):
|
30
|
+
continue
|
31
|
+
|
32
|
+
arg_type = (
|
33
|
+
param.annotation if param.annotation is not inspect.Parameter.empty else str
|
34
|
+
)
|
35
|
+
default = param.default if param.default is not inspect.Parameter.empty else None
|
36
|
+
is_required = param.default is inspect.Parameter.empty
|
37
|
+
if is_required:
|
38
|
+
flags = [f"{name.replace('_', '-')}"]
|
39
|
+
else:
|
40
|
+
flags = [f"--{name.replace('_', '-')}"]
|
41
|
+
action = "store"
|
42
|
+
nargs: int | str = 1
|
43
|
+
|
44
|
+
if arg_type is bool:
|
45
|
+
if param.default is False:
|
46
|
+
action = "store_true"
|
47
|
+
else:
|
48
|
+
action = "store_false"
|
49
|
+
|
50
|
+
if arg_type is list:
|
51
|
+
action = "append"
|
52
|
+
if is_required:
|
53
|
+
nargs = "+"
|
54
|
+
else:
|
55
|
+
nargs = "*"
|
56
|
+
|
57
|
+
arg_defs.append(
|
58
|
+
{
|
59
|
+
"flags": flags,
|
60
|
+
"dest": name,
|
61
|
+
"type": arg_type,
|
62
|
+
"default": default,
|
63
|
+
"required": is_required,
|
64
|
+
"nargs": nargs,
|
65
|
+
"action": action,
|
66
|
+
"help": metadata.get("help", ""),
|
67
|
+
"choices": metadata.get("choices"),
|
68
|
+
}
|
69
|
+
)
|
70
|
+
|
71
|
+
return arg_defs
|
falyx/parsers/utils.py
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from falyx import logger
|
4
|
+
from falyx.action.action import Action, ChainedAction, ProcessAction
|
5
|
+
from falyx.parsers.signature import infer_args_from_func
|
6
|
+
|
7
|
+
|
8
|
+
def same_argument_definitions(
|
9
|
+
actions: list[Any],
|
10
|
+
arg_metadata: dict[str, str | dict[str, Any]] | None = None,
|
11
|
+
) -> list[dict[str, Any]] | None:
|
12
|
+
arg_sets = []
|
13
|
+
for action in actions:
|
14
|
+
if isinstance(action, (Action, ProcessAction)):
|
15
|
+
arg_defs = infer_args_from_func(action.action, arg_metadata)
|
16
|
+
elif isinstance(action, ChainedAction):
|
17
|
+
if action.actions:
|
18
|
+
action = action.actions[0]
|
19
|
+
if isinstance(action, Action):
|
20
|
+
arg_defs = infer_args_from_func(action.action, arg_metadata)
|
21
|
+
elif callable(action):
|
22
|
+
arg_defs = infer_args_from_func(action, arg_metadata)
|
23
|
+
elif callable(action):
|
24
|
+
arg_defs = infer_args_from_func(action, arg_metadata)
|
25
|
+
else:
|
26
|
+
logger.debug("Auto args unsupported for action: %s", action)
|
27
|
+
return None
|
28
|
+
arg_sets.append(arg_defs)
|
29
|
+
|
30
|
+
first = arg_sets[0]
|
31
|
+
if all(arg_set == first for arg_set in arg_sets[1:]):
|
32
|
+
return first
|
33
|
+
return None
|
falyx/protocols.py
CHANGED
@@ -2,10 +2,16 @@
|
|
2
2
|
"""protocols.py"""
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from typing import Any, Awaitable, Protocol
|
5
|
+
from typing import Any, Awaitable, Protocol, runtime_checkable
|
6
6
|
|
7
7
|
from falyx.action.action import BaseAction
|
8
8
|
|
9
9
|
|
10
|
+
@runtime_checkable
|
10
11
|
class ActionFactoryProtocol(Protocol):
|
11
12
|
async def __call__(self, *args: Any, **kwargs: Any) -> Awaitable[BaseAction]: ...
|
13
|
+
|
14
|
+
|
15
|
+
@runtime_checkable
|
16
|
+
class ArgParserProtocol(Protocol):
|
17
|
+
def __call__(self, args: list[str]) -> tuple[tuple, dict]: ...
|
falyx/signals.py
CHANGED
@@ -29,3 +29,10 @@ class CancelSignal(FlowSignal):
|
|
29
29
|
|
30
30
|
def __init__(self, message: str = "Cancel signal received."):
|
31
31
|
super().__init__(message)
|
32
|
+
|
33
|
+
|
34
|
+
class HelpSignal(FlowSignal):
|
35
|
+
"""Raised to display help information."""
|
36
|
+
|
37
|
+
def __init__(self, message: str = "Help signal received."):
|
38
|
+
super().__init__(message)
|
falyx/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.29"
|
@@ -1,11 +1,12 @@
|
|
1
1
|
falyx/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
falyx/__init__.py,sha256=L40665QyjAqHQxHdxxY2_yPeDa4p0LE7Nu_2dkm08Ls,650
|
3
3
|
falyx/__main__.py,sha256=g_LwJieofK3DJzCYtpkAMEeOXhzSLQenb7pRVUqcf-Y,2152
|
4
|
+
falyx/action/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
5
|
falyx/action/__init__.py,sha256=zpOK5g4DybydV8d3QI0Zq52aWaKFPYi-J6szAQTsQ2c,974
|
5
6
|
falyx/action/action.py,sha256=CJB9eeeEqBGkZHjMpG24eXHRjouKSfESCI1zWzoE7JQ,32488
|
6
7
|
falyx/action/action_factory.py,sha256=qNtEnsbKsNl-WijChbTQYfdI3k14fN-1bzDsGFx8yZI,4517
|
7
8
|
falyx/action/http_action.py,sha256=aIieGHyZSkz1ZGay-fwgDYZ0QF17XypAWtKeVAYp5f4,5806
|
8
|
-
falyx/action/io_action.py,sha256=
|
9
|
+
falyx/action/io_action.py,sha256=Xy4k4Zx5qrrRs7Y7NZE5qCzAnHe6iJMkVrPZ8KpDD0k,9850
|
9
10
|
falyx/action/menu_action.py,sha256=cboCpXyl0fZUxpFsvEPu0dGhFfr_vdfllceQnICA0gU,5683
|
10
11
|
falyx/action/select_file_action.py,sha256=hHLhmTSacWaUXhRTeIIiXt8gR7zbjkXJ2MAkKQYCpp4,7799
|
11
12
|
falyx/action/selection_action.py,sha256=22rF7UqRrQAMjGIheDqAbUizVMBg9aCl9e4VOLLZZJo,8811
|
@@ -13,35 +14,39 @@ falyx/action/signal_action.py,sha256=5UMqvzy7fBnLANGwYUWoe1VRhrr7e-yOVeLdOnCBiJo
|
|
13
14
|
falyx/action/types.py,sha256=iVD-bHm1GRXOTIlHOeT_KcDBRZm4Hz5Xzl_BOalvEf4,961
|
14
15
|
falyx/action/user_input_action.py,sha256=LSTzC_3TfsfXdz-qV3GlOIGpZWAOgO9J5DnNsHO7ee8,3398
|
15
16
|
falyx/bottom_bar.py,sha256=iWxgOKWgn5YmREeZBuGA50FzqzEfz1-Vnqm0V_fhldc,7383
|
16
|
-
falyx/command.py,sha256=
|
17
|
+
falyx/command.py,sha256=YTkLFzVwKNmVkRRL237qbEMD8lpYycRaVtKVn4rt2OQ,16177
|
17
18
|
falyx/config.py,sha256=8dkQfL-Ro-vWw1AcO2fD1PGZ92Cyfnwl885ZlpLkp4Y,9636
|
18
|
-
falyx/config_schema.py,sha256=j5GQuHVlaU-VLxLF9t8idZRjqOP9MIKp1hyd9NhpAGU,3124
|
19
19
|
falyx/context.py,sha256=FNF-IS7RMDxel2l3kskEqQImZ0mLO6zvGw_xC9cIzgI,10338
|
20
20
|
falyx/debug.py,sha256=oWWTLOF8elrx_RGZ1G4pbzfFr46FjB0woFXpVU2wmjU,1567
|
21
|
-
falyx/exceptions.py,sha256=
|
21
|
+
falyx/exceptions.py,sha256=kK9k1v7LVNjJSwYztRa9Krhr3ZOI-6Htq2ZjlYICPKg,922
|
22
22
|
falyx/execution_registry.py,sha256=rctsz0mrIHPToLZqylblVjDdKWdq1x_JBc8GwMP5sJ8,4710
|
23
|
-
falyx/falyx.py,sha256=
|
23
|
+
falyx/falyx.py,sha256=TX446soM31kq3pNCsGWcrxDtZoQQlgtcfRCJ1OMq5XY,44595
|
24
24
|
falyx/hook_manager.py,sha256=GuGxVVz9FXrU39Tk220QcsLsMXeut7ZDkGW3hU9GcwQ,2952
|
25
25
|
falyx/hooks.py,sha256=IV2nbj5FjY2m3_L7x4mYBnaRDG45E8tWQU90i4butlw,2940
|
26
26
|
falyx/init.py,sha256=abcSlPmxVeByLIHdUkNjqtO_tEkO3ApC6f9WbxsSEWg,3393
|
27
27
|
falyx/logger.py,sha256=1Mfb_vJFJ1tQwziuyU2p-cSMi2Js8N2byniFEnI6vOQ,132
|
28
28
|
falyx/menu.py,sha256=faxGgocqQYY6HtzVbenHaFj8YqsmycBEyziC8Ahzqjo,2870
|
29
29
|
falyx/options_manager.py,sha256=dFAnQw543tQ6Xupvh1PwBrhiSWlSACHw8K-sHP_lUh4,2842
|
30
|
-
falyx/parsers
|
30
|
+
falyx/parsers/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
|
+
falyx/parsers/__init__.py,sha256=Z5HjwqVlf2Bp8STSz3XMMYWWkkerRS0MDGf_Y4KXGVA,520
|
32
|
+
falyx/parsers/argparse.py,sha256=ElWg4nl1ygkDY9Q4lTfjj4KMXI0FKDLVdc08eiGw4AQ,29889
|
33
|
+
falyx/parsers/parsers.py,sha256=KsDFEmJLM86d2X4Kh4SHA9mBbUk351NjLhhFYzQkaPk,5762
|
34
|
+
falyx/parsers/signature.py,sha256=mDMgg-H27OKqrORksIbQSETfEUoL_DaHKVnDviCLsCQ,2125
|
35
|
+
falyx/parsers/utils.py,sha256=3kjvrYBnvw90b1ALrAaRWUkQU7axLY9XqJOmf8W1BAQ,1230
|
31
36
|
falyx/prompt_utils.py,sha256=qgk0bXs7mwzflqzWyFhEOTpKQ_ZtMIqGhKeg-ocwNnE,1542
|
32
|
-
falyx/protocols.py,sha256=
|
37
|
+
falyx/protocols.py,sha256=mesdq5CjPF_5Kyu7Evwr6qMT71tUHlw0SjjtmnggTZw,495
|
33
38
|
falyx/retry.py,sha256=UUzY6FlKobr84Afw7yJO9rj3AIQepDk2fcWs6_1gi6Q,3788
|
34
39
|
falyx/retry_utils.py,sha256=EAzc-ECTu8AxKkmlw28ioOW9y-Y9tLQ0KasvSkBRYgs,694
|
35
40
|
falyx/selection.py,sha256=l2LLISqgP8xfHdcTAEbTTqs_Bae4-LVUKMN7VQH7tM0,10731
|
36
|
-
falyx/signals.py,sha256=
|
41
|
+
falyx/signals.py,sha256=Y_neFXpfHs7qY0syw9XcfR9WeAGRcRw1nG_2L1JJqKE,1083
|
37
42
|
falyx/tagged_table.py,sha256=4SV-SdXFrAhy1JNToeBCvyxT-iWVf6cWY7XETTys4n8,1067
|
38
43
|
falyx/themes/__init__.py,sha256=1CZhEUCin9cUk8IGYBUFkVvdHRNNJBEFXccHwpUKZCA,284
|
39
44
|
falyx/themes/colors.py,sha256=4aaeAHJetmeNInI0Zytg4E3YqKfPFelpf04vtjSvsS8,19776
|
40
45
|
falyx/utils.py,sha256=u3puR4Bh-unNBw9a0V9sw7PDTIzRaNLolap0oz5bVIk,6718
|
41
46
|
falyx/validators.py,sha256=t5iyzVpY8tdC4rfhr4isEfWpD5gNTzjeX_Hbi_Uq6sA,1328
|
42
|
-
falyx/version.py,sha256=
|
43
|
-
falyx-0.1.
|
44
|
-
falyx-0.1.
|
45
|
-
falyx-0.1.
|
46
|
-
falyx-0.1.
|
47
|
-
falyx-0.1.
|
47
|
+
falyx/version.py,sha256=A-lFHZ4YpCrWZ6nw3tlt_yurFJ00mInm3gR6hz51Eww,23
|
48
|
+
falyx-0.1.29.dist-info/LICENSE,sha256=B0yqgaHuSdhN7T3OBmgQSiDTy8HqT5Oe_dLypRe4Ra4,1073
|
49
|
+
falyx-0.1.29.dist-info/METADATA,sha256=cUcRdSgrw8TPfn21pRyn7mS-WrvpvWChdwPd4ikSCQQ,5521
|
50
|
+
falyx-0.1.29.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
51
|
+
falyx-0.1.29.dist-info/entry_points.txt,sha256=j8owOSl2j1Ss8DtGMnKfgehKaolqnIPhVFHaUBLUnMs,45
|
52
|
+
falyx-0.1.29.dist-info/RECORD,,
|
falyx/config_schema.py
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
FALYX_CONFIG_SCHEMA = {
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
3
|
-
"title": "Falyx CLI Config",
|
4
|
-
"type": "object",
|
5
|
-
"properties": {
|
6
|
-
"title": {"type": "string", "description": "Title shown at top of menu"},
|
7
|
-
"prompt": {
|
8
|
-
"oneOf": [
|
9
|
-
{"type": "string"},
|
10
|
-
{
|
11
|
-
"type": "array",
|
12
|
-
"items": {
|
13
|
-
"type": "array",
|
14
|
-
"prefixItems": [
|
15
|
-
{
|
16
|
-
"type": "string",
|
17
|
-
"description": "Style string (e.g., 'bold #ff0000 italic')",
|
18
|
-
},
|
19
|
-
{"type": "string", "description": "Text content"},
|
20
|
-
],
|
21
|
-
"minItems": 2,
|
22
|
-
"maxItems": 2,
|
23
|
-
},
|
24
|
-
},
|
25
|
-
]
|
26
|
-
},
|
27
|
-
"columns": {
|
28
|
-
"type": "integer",
|
29
|
-
"minimum": 1,
|
30
|
-
"description": "Number of menu columns",
|
31
|
-
},
|
32
|
-
"welcome_message": {"type": "string"},
|
33
|
-
"exit_message": {"type": "string"},
|
34
|
-
"commands": {
|
35
|
-
"type": "array",
|
36
|
-
"items": {
|
37
|
-
"type": "object",
|
38
|
-
"required": ["key", "description", "action"],
|
39
|
-
"properties": {
|
40
|
-
"key": {"type": "string", "minLength": 1},
|
41
|
-
"description": {"type": "string"},
|
42
|
-
"action": {
|
43
|
-
"type": "string",
|
44
|
-
"pattern": "^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)+$",
|
45
|
-
"description": "Dotted import path (e.g., mymodule.task)",
|
46
|
-
},
|
47
|
-
"args": {"type": "array"},
|
48
|
-
"kwargs": {"type": "object"},
|
49
|
-
"aliases": {"type": "array", "items": {"type": "string"}},
|
50
|
-
"tags": {"type": "array", "items": {"type": "string"}},
|
51
|
-
"style": {"type": "string"},
|
52
|
-
"confirm": {"type": "boolean"},
|
53
|
-
"confirm_message": {"type": "string"},
|
54
|
-
"preview_before_confirm": {"type": "boolean"},
|
55
|
-
"spinner": {"type": "boolean"},
|
56
|
-
"spinner_message": {"type": "string"},
|
57
|
-
"spinner_type": {"type": "string"},
|
58
|
-
"spinner_style": {"type": "string"},
|
59
|
-
"logging_hooks": {"type": "boolean"},
|
60
|
-
"retry": {"type": "boolean"},
|
61
|
-
"retry_all": {"type": "boolean"},
|
62
|
-
"retry_policy": {
|
63
|
-
"type": "object",
|
64
|
-
"properties": {
|
65
|
-
"enabled": {"type": "boolean"},
|
66
|
-
"max_retries": {"type": "integer"},
|
67
|
-
"delay": {"type": "number"},
|
68
|
-
"backoff": {"type": "number"},
|
69
|
-
},
|
70
|
-
},
|
71
|
-
},
|
72
|
-
},
|
73
|
-
},
|
74
|
-
},
|
75
|
-
"required": ["commands"],
|
76
|
-
}
|
File without changes
|
File without changes
|
File without changes
|