shvcli 0.6.1__tar.gz → 0.7.0__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.
Files changed (58) hide show
  1. {shvcli-0.6.1/shvcli.egg-info → shvcli-0.7.0}/PKG-INFO +43 -26
  2. {shvcli-0.6.1 → shvcli-0.7.0}/README.rst +38 -22
  3. {shvcli-0.6.1 → shvcli-0.7.0}/pyproject.toml +3 -5
  4. shvcli-0.7.0/shvcli/__init__.py +55 -0
  5. shvcli-0.7.0/shvcli/__main__.py +36 -0
  6. shvcli-0.7.0/shvcli/afterconn.py +55 -0
  7. shvcli-0.7.0/shvcli/args.py +56 -0
  8. shvcli-0.7.0/shvcli/builtin.py +86 -0
  9. shvcli-0.7.0/shvcli/builtins/__init__.py +27 -0
  10. shvcli-0.7.0/shvcli/builtins/broker.py +100 -0
  11. shvcli-0.7.0/shvcli/builtins/cd.py +37 -0
  12. shvcli-0.7.0/shvcli/builtins/file.py +128 -0
  13. shvcli-0.7.0/shvcli/builtins/help.py +58 -0
  14. shvcli-0.7.0/shvcli/builtins/scan.py +41 -0
  15. shvcli-0.7.0/shvcli/builtins/set.py +70 -0
  16. shvcli-0.7.0/shvcli/builtins/tree.py +66 -0
  17. shvcli-0.7.0/shvcli/cli.py +184 -0
  18. shvcli-0.7.0/shvcli/client.py +133 -0
  19. shvcli-0.7.0/shvcli/cliitems.py +88 -0
  20. shvcli-0.7.0/shvcli/complet.py +86 -0
  21. shvcli-0.7.0/shvcli/config.py +106 -0
  22. shvcli-0.7.0/shvcli/file.py +68 -0
  23. shvcli-0.7.0/shvcli/lsdir.py +127 -0
  24. shvcli-0.7.0/shvcli/option.py +267 -0
  25. shvcli-0.7.0/shvcli/options.py +168 -0
  26. shvcli-0.7.0/shvcli/plugins.py +18 -0
  27. {shvcli-0.6.1 → shvcli-0.7.0}/shvcli/scan.py +7 -7
  28. shvcli-0.7.0/shvcli/state.py +96 -0
  29. shvcli-0.7.0/shvcli/tools/__init__.py +1 -0
  30. shvcli-0.7.0/shvcli/tools/complet.py +60 -0
  31. shvcli-0.6.1/shvcli/tools.py → shvcli-0.7.0/shvcli/tools/print.py +15 -28
  32. shvcli-0.7.0/shvcli/tree.py +126 -0
  33. shvcli-0.7.0/shvcli/url.py +110 -0
  34. shvcli-0.7.0/shvcli/valid.py +78 -0
  35. {shvcli-0.6.1 → shvcli-0.7.0/shvcli.egg-info}/PKG-INFO +43 -26
  36. shvcli-0.7.0/shvcli.egg-info/SOURCES.txt +42 -0
  37. {shvcli-0.6.1 → shvcli-0.7.0}/shvcli.egg-info/requires.txt +2 -1
  38. shvcli-0.6.1/shvcli/__init__.py +0 -5
  39. shvcli-0.6.1/shvcli/__main__.py +0 -62
  40. shvcli-0.6.1/shvcli/builtin.py +0 -132
  41. shvcli-0.6.1/shvcli/builtin_impl.py +0 -170
  42. shvcli-0.6.1/shvcli/cli.py +0 -136
  43. shvcli-0.6.1/shvcli/client.py +0 -210
  44. shvcli-0.6.1/shvcli/complet.py +0 -78
  45. shvcli-0.6.1/shvcli/complet_tools.py +0 -64
  46. shvcli-0.6.1/shvcli/config.py +0 -176
  47. shvcli-0.6.1/shvcli/lsdir.py +0 -145
  48. shvcli-0.6.1/shvcli/parse.py +0 -87
  49. shvcli-0.6.1/shvcli/valid.py +0 -41
  50. shvcli-0.6.1/shvcli/version +0 -1
  51. shvcli-0.6.1/shvcli.egg-info/SOURCES.txt +0 -26
  52. {shvcli-0.6.1 → shvcli-0.7.0}/LICENSE +0 -0
  53. {shvcli-0.6.1 → shvcli-0.7.0}/setup.cfg +0 -0
  54. {shvcli-0.6.1 → shvcli-0.7.0}/shvcli/__version__.py +0 -0
  55. {shvcli-0.6.1 → shvcli-0.7.0}/shvcli/py.typed +0 -0
  56. {shvcli-0.6.1 → shvcli-0.7.0}/shvcli.egg-info/dependency_links.txt +0 -0
  57. {shvcli-0.6.1 → shvcli-0.7.0}/shvcli.egg-info/entry_points.txt +0 -0
  58. {shvcli-0.6.1 → shvcli-0.7.0}/shvcli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: shvcli
3
- Version: 0.6.1
3
+ Version: 0.7.0
4
4
  Summary: Silicon Heaven CLI access application
5
5
  Author: Elektroline a.s.
6
6
  License: MIT License
@@ -27,7 +27,6 @@ License: MIT License
27
27
 
28
28
  Project-URL: repository, https://gitlab.com/silicon-heaven/shvcli
29
29
  Classifier: Development Status :: 4 - Beta
30
- Classifier: License :: OSI Approved :: MIT License
31
30
  Classifier: Programming Language :: Python :: 3
32
31
  Classifier: Operating System :: OS Independent
33
32
  Classifier: Environment :: Console
@@ -38,10 +37,12 @@ Classifier: Topic :: Terminals
38
37
  Requires-Python: >=3.11
39
38
  Description-Content-Type: text/x-rst
40
39
  License-File: LICENSE
41
- Requires-Dist: pyshv>=0.7.1
40
+ Requires-Dist: pyshv>=0.9.0
42
41
  Requires-Dist: prompt_toolkit
43
42
  Requires-Dist: pygments
44
43
  Requires-Dist: pyxdg
44
+ Requires-Dist: more-itertools
45
+ Dynamic: license-file
45
46
 
46
47
  =====================================
47
48
  Silicon Heaven CLI access application
@@ -101,20 +102,25 @@ An example of usage:
101
102
  .app> /:
102
103
  >
103
104
 
105
+ .. TIP::
106
+ The validation that is performed by SHVCLI is best effort and sometimes you
107
+ might need to submit call that is considered invalid by SHVCLI. For that
108
+ reason you can use `Ctrl+o` shortcut instead of pressing enter key.
109
+
104
110
 
105
111
  Configuration file
106
112
  ------------------
107
113
 
108
- Tool reads configuration from files ``/etc/shvcli.ini`` and ``~/.shvcli.ini``.
109
- They are in INI file format and the following sections are supported:
114
+ Tool reads configuration from files ``/etc/shvcli.toml`` and ``~/.shvcli.toml``.
115
+ They are in TOML file format and the following sections are supported:
110
116
 
111
117
  **hosts**: That provides mapping from some name to RPC URL.
112
118
 
113
119
  **hosts-shell**: That is same as **hosts** with exception that URL is passed
114
120
  through your local Shell to expand any variables or command substitutions.
115
121
 
116
- **config**: That allows you to set some initial configuration that can be also
117
- switched in runtime. The following options are available:
122
+ **option**: That allows you to set initial setting for runtime options. The
123
+ following options are available without any plugins:
118
124
 
119
125
  * **vimode**: If Vi input mode should be used for command line input. The
120
126
  default is ``false``.
@@ -137,17 +143,15 @@ switched in runtime. The following options are available:
137
143
  be also overwhelming. The default is ``false``. It is beneficial to disable
138
144
  the **autobrobe** once you enable debug because otherwise output on CLI will
139
145
  be mangled on completion.
140
- * **cache**: Controls if cache is preserved between invocations. Cache is
141
- separated based on the connection URL and stored in files in
142
- ``$XDG_CACHE_HOME/shvcli``. The default is ``true``.
143
- * **call_attempts**: Number of attempts before method call is abandoned and
144
- timeout is reported. This makes the total time multiple of **call_timeout**.
145
- * **call_timeout**: Timeout in seconds before call attempt is abandoned. Based
146
- on the **call_attempts** call is attempted again or timeout is reported.
147
- * **autoget_timeout**: Timeout in seconds before call that is part of autoget
146
+ * **call_query_timeout**: Timeout in seconds for status request query. The
147
+ shorter time will result in faster request lost detection while very short
148
+ time will load SHV network too much.
149
+ * **call_retry_timeout**: Timeout in seconds when call request is sent again if
150
+ no response is received. This is not applied if query is and thus this mostly
151
+ is used only in case when method doesn't support delayed responses.
152
+ * **autoget_timeout**: Timeout in seconds for call that is part of autoget
148
153
  functionality.
149
154
 
150
-
151
155
  Example configuration file:
152
156
 
153
157
  .. code-block:: ini
@@ -172,10 +176,7 @@ environment you are running in.
172
176
 
173
177
  **subscribe|sub**: Add new subscribe. Shortcut to the call of
174
178
  ``.app/broker/currentClient:subscribe`` that accepts arguments in more convenient
175
- way (you need to use Map if you call that method directly). The argument has
176
- same format such as method calls in this tool, that means ``PATH:METHOD`` where
177
- ``METHOD`` can be left out to match all methods. Pattern subscribes are not
178
- supporter, yet.
179
+ way. The argument can be multiple RPC RIs (``PATH:METHOD:SIGNAL`` patterns).
179
180
 
180
181
  **unsubscribe|usub**: Unsubscribe existing subscription. It is reverse operation
181
182
  to the **subscribe** and same remarks apply here as well. It is a shortcut to
@@ -197,11 +198,20 @@ cache.
197
198
  thus use it sparely.
198
199
 
199
200
  **set|s**: allows modification of configuration option in runtime. The names
200
- are the same as in ``config`` section. The boolean options (the only ones
201
- available right now) are set if no argument is provided, or cleared if name is
202
- prefixed with ``no`` (and thus to disable ``raw`` you use ``noraw``). You can
203
- also provide argument ``true`` or ``false``. Without any configuration option it
204
- simply prints the current configuration.
201
+ are the same as in ``config`` section. The boolean options are set if no
202
+ argument is provided, or cleared if name is prefixed with ``no`` (and thus to
203
+ disable ``raw`` you use ``noraw``). You can also add ``=true`` or ``=false``.
204
+ The equal sign is also used with integer and floating point options. Without any
205
+ configuration option it simply prints the current configuration.
206
+
207
+ **upload**: provides a way to copy local file to the RPC File node. The
208
+ parameter must be path to the local file to be uploaded.
209
+
210
+ **download**: provides a way to copy RPC File node data to local file. The
211
+ parameter must be path to the local file where data will be stored.
212
+
213
+ **verify**: provides a way to verify RPC File node against local file. The
214
+ parameter must be path to the local file used for the verification.
205
215
 
206
216
 
207
217
  Special methods ``ls`` and ``dir``
@@ -214,3 +224,10 @@ the fullest content.
214
224
  Their parameter is also handled in a special way. It is considered to be
215
225
  additional path suffix unless it is a valid CPON. This is allowed to match the
216
226
  common shells.
227
+
228
+
229
+ Plugins
230
+ -------
231
+
232
+ The support for external plugins is provided. These plugins are discovered using
233
+ Python package metadata using the entry point ``shvcli.plugins``.
@@ -56,20 +56,25 @@ An example of usage:
56
56
  .app> /:
57
57
  >
58
58
 
59
+ .. TIP::
60
+ The validation that is performed by SHVCLI is best effort and sometimes you
61
+ might need to submit call that is considered invalid by SHVCLI. For that
62
+ reason you can use `Ctrl+o` shortcut instead of pressing enter key.
63
+
59
64
 
60
65
  Configuration file
61
66
  ------------------
62
67
 
63
- Tool reads configuration from files ``/etc/shvcli.ini`` and ``~/.shvcli.ini``.
64
- They are in INI file format and the following sections are supported:
68
+ Tool reads configuration from files ``/etc/shvcli.toml`` and ``~/.shvcli.toml``.
69
+ They are in TOML file format and the following sections are supported:
65
70
 
66
71
  **hosts**: That provides mapping from some name to RPC URL.
67
72
 
68
73
  **hosts-shell**: That is same as **hosts** with exception that URL is passed
69
74
  through your local Shell to expand any variables or command substitutions.
70
75
 
71
- **config**: That allows you to set some initial configuration that can be also
72
- switched in runtime. The following options are available:
76
+ **option**: That allows you to set initial setting for runtime options. The
77
+ following options are available without any plugins:
73
78
 
74
79
  * **vimode**: If Vi input mode should be used for command line input. The
75
80
  default is ``false``.
@@ -92,17 +97,15 @@ switched in runtime. The following options are available:
92
97
  be also overwhelming. The default is ``false``. It is beneficial to disable
93
98
  the **autobrobe** once you enable debug because otherwise output on CLI will
94
99
  be mangled on completion.
95
- * **cache**: Controls if cache is preserved between invocations. Cache is
96
- separated based on the connection URL and stored in files in
97
- ``$XDG_CACHE_HOME/shvcli``. The default is ``true``.
98
- * **call_attempts**: Number of attempts before method call is abandoned and
99
- timeout is reported. This makes the total time multiple of **call_timeout**.
100
- * **call_timeout**: Timeout in seconds before call attempt is abandoned. Based
101
- on the **call_attempts** call is attempted again or timeout is reported.
102
- * **autoget_timeout**: Timeout in seconds before call that is part of autoget
100
+ * **call_query_timeout**: Timeout in seconds for status request query. The
101
+ shorter time will result in faster request lost detection while very short
102
+ time will load SHV network too much.
103
+ * **call_retry_timeout**: Timeout in seconds when call request is sent again if
104
+ no response is received. This is not applied if query is and thus this mostly
105
+ is used only in case when method doesn't support delayed responses.
106
+ * **autoget_timeout**: Timeout in seconds for call that is part of autoget
103
107
  functionality.
104
108
 
105
-
106
109
  Example configuration file:
107
110
 
108
111
  .. code-block:: ini
@@ -127,10 +130,7 @@ environment you are running in.
127
130
 
128
131
  **subscribe|sub**: Add new subscribe. Shortcut to the call of
129
132
  ``.app/broker/currentClient:subscribe`` that accepts arguments in more convenient
130
- way (you need to use Map if you call that method directly). The argument has
131
- same format such as method calls in this tool, that means ``PATH:METHOD`` where
132
- ``METHOD`` can be left out to match all methods. Pattern subscribes are not
133
- supporter, yet.
133
+ way. The argument can be multiple RPC RIs (``PATH:METHOD:SIGNAL`` patterns).
134
134
 
135
135
  **unsubscribe|usub**: Unsubscribe existing subscription. It is reverse operation
136
136
  to the **subscribe** and same remarks apply here as well. It is a shortcut to
@@ -152,11 +152,20 @@ cache.
152
152
  thus use it sparely.
153
153
 
154
154
  **set|s**: allows modification of configuration option in runtime. The names
155
- are the same as in ``config`` section. The boolean options (the only ones
156
- available right now) are set if no argument is provided, or cleared if name is
157
- prefixed with ``no`` (and thus to disable ``raw`` you use ``noraw``). You can
158
- also provide argument ``true`` or ``false``. Without any configuration option it
159
- simply prints the current configuration.
155
+ are the same as in ``config`` section. The boolean options are set if no
156
+ argument is provided, or cleared if name is prefixed with ``no`` (and thus to
157
+ disable ``raw`` you use ``noraw``). You can also add ``=true`` or ``=false``.
158
+ The equal sign is also used with integer and floating point options. Without any
159
+ configuration option it simply prints the current configuration.
160
+
161
+ **upload**: provides a way to copy local file to the RPC File node. The
162
+ parameter must be path to the local file to be uploaded.
163
+
164
+ **download**: provides a way to copy RPC File node data to local file. The
165
+ parameter must be path to the local file where data will be stored.
166
+
167
+ **verify**: provides a way to verify RPC File node against local file. The
168
+ parameter must be path to the local file used for the verification.
160
169
 
161
170
 
162
171
  Special methods ``ls`` and ``dir``
@@ -169,3 +178,10 @@ the fullest content.
169
178
  Their parameter is also handled in a special way. It is considered to be
170
179
  additional path suffix unless it is a valid CPON. This is allowed to match the
171
180
  common shells.
181
+
182
+
183
+ Plugins
184
+ -------
185
+
186
+ The support for external plugins is provided. These plugins are discovered using
187
+ Python package metadata using the entry point ``shvcli.plugins``.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "shvcli"
3
- version = "0.6.1"
3
+ version = "0.7.0"
4
4
  description = "Silicon Heaven CLI access application"
5
5
  readme = "README.rst"
6
6
  license = {file = "LICENSE"}
@@ -9,7 +9,6 @@ authors = [
9
9
  ]
10
10
  classifiers = [
11
11
  "Development Status :: 4 - Beta",
12
- "License :: OSI Approved :: MIT License",
13
12
  "Programming Language :: Python :: 3",
14
13
  "Operating System :: OS Independent",
15
14
  "Environment :: Console",
@@ -20,10 +19,11 @@ classifiers = [
20
19
  ]
21
20
  requires-python = ">=3.11"
22
21
  dependencies = [
23
- "pyshv >= 0.7.1",
22
+ "pyshv >= 0.9.0",
24
23
  "prompt_toolkit",
25
24
  "pygments",
26
25
  "pyxdg",
26
+ "more-itertools",
27
27
  ]
28
28
 
29
29
  [project.urls]
@@ -77,8 +77,6 @@ ignore = [
77
77
  "PLR0916",
78
78
  # This seems like a wrong rule
79
79
  "PLW1641",
80
- # Deprecated
81
- "ANN101", "ANN102",
82
80
  ]
83
81
  preview = true
84
82
  [tool.ruff.lint.per-file-ignores]
@@ -0,0 +1,55 @@
1
+ """Silicon Heaven Command Line Interface."""
2
+
3
+ import importlib
4
+
5
+ from .__version__ import VERSION
6
+ from .args import register_argparser
7
+ from .builtin import Builtin, Builtins
8
+ from .client import Client
9
+ from .cliitems import CliItems
10
+ from .config import Config, ConfigError, register_config
11
+ from .option import BoolOption, FloatOption, IntOption, Option
12
+ from .options import (
13
+ AutoGetOption,
14
+ AutoGetTimeoutOption,
15
+ AutoProbeOption,
16
+ CallDuration,
17
+ CallQueryTimeout,
18
+ CallRetryTimeout,
19
+ DebugOption,
20
+ RawOption,
21
+ ViModeOption,
22
+ )
23
+ from .state import State, StateVar
24
+ from .tree import Node, Tree
25
+
26
+ __all__ = [
27
+ "VERSION",
28
+ "AutoGetOption",
29
+ "AutoGetTimeoutOption",
30
+ "AutoProbeOption",
31
+ "BoolOption",
32
+ "Builtin",
33
+ "Builtins",
34
+ "CallDuration",
35
+ "CallQueryTimeout",
36
+ "CallRetryTimeout",
37
+ "CliItems",
38
+ "Client",
39
+ "Config",
40
+ "ConfigError",
41
+ "DebugOption",
42
+ "FloatOption",
43
+ "IntOption",
44
+ "Node",
45
+ "Option",
46
+ "RawOption",
47
+ "State",
48
+ "StateVar",
49
+ "Tree",
50
+ "ViModeOption",
51
+ "register_argparser",
52
+ "register_config",
53
+ ]
54
+
55
+ importlib.import_module(".builtins", package=__package__)
@@ -0,0 +1,36 @@
1
+ """Implementation of command line application."""
2
+
3
+ import asyncio
4
+
5
+ from .afterconn import Afterconn
6
+ from .args import args_apply, args_parse
7
+ from .cli import run
8
+ from .client import Client
9
+ from .config import load_config
10
+ from .plugins import load_plugins
11
+ from .state import State
12
+ from .url import Url
13
+
14
+
15
+ def main() -> None:
16
+ """Application's entrypoint."""
17
+ load_plugins()
18
+ argsgens, args = args_parse()
19
+ state = State()
20
+ load_config(args.config, state)
21
+ args_apply(argsgens, args, state)
22
+ state.cache_load(Url(state).cache_path())
23
+
24
+ async def async_main() -> None:
25
+ client = await Client.connect(Url(state).url, state=state)
26
+ await Afterconn(state).run(client)
27
+ await run(client)
28
+ if client.client.connected:
29
+ await client.disconnect()
30
+
31
+ asyncio.run(async_main())
32
+ state.cache_dump(Url(state).cache_path())
33
+
34
+
35
+ if __name__ == "__main__":
36
+ main()
@@ -0,0 +1,55 @@
1
+ """The after connection tasks."""
2
+
3
+ import argparse
4
+ import collections.abc
5
+ import typing
6
+
7
+ from .args import ArgsParseFuncGenT, register_argparser
8
+ from .client import Client, SHVPath
9
+ from .cliitems import CliItems
10
+ from .scan import scan_nodes
11
+ from .state import StateVar
12
+
13
+ AfterConnT: typing.TypeAlias = collections.abc.Callable[
14
+ [Client], collections.abc.Coroutine[None, None, None]
15
+ ]
16
+
17
+
18
+ class Afterconn(StateVar, list[AfterConnT]):
19
+ """The set of operations to be performed right after connection."""
20
+
21
+ async def run(self, client: Client) -> None:
22
+ """Run the steps setup to be performed after connection at startup."""
23
+ for func in self:
24
+ await func(client)
25
+
26
+
27
+ @register_argparser
28
+ def _argparser(parser: argparse.ArgumentParser) -> ArgsParseFuncGenT:
29
+ parser.add_argument(
30
+ "-s",
31
+ "--subscribe",
32
+ action="append",
33
+ default=[],
34
+ help="Automatic subscription right after connection.",
35
+ )
36
+ parser.add_argument(
37
+ "--scan",
38
+ action="store_true",
39
+ help="Perform scan as a first action right after connect.",
40
+ )
41
+ parser.add_argument(
42
+ "--scan-depth",
43
+ type=int,
44
+ default=3,
45
+ help="Depth of the scan performed if --scan is used.",
46
+ )
47
+ args, state = yield
48
+
49
+ async def afterconn(client: Client) -> None:
50
+ for ri in args.subscribe:
51
+ await client.subscribe(CliItems.extend_ri(ri))
52
+ if args.scan:
53
+ await scan_nodes(client, SHVPath(""), args.scan_dept)
54
+
55
+ Afterconn(state).append(afterconn)
@@ -0,0 +1,56 @@
1
+ """Argument parser wrapper for the SHVCLI."""
2
+
3
+ import argparse
4
+ import collections.abc
5
+ import contextlib
6
+ import pathlib
7
+ import typing
8
+
9
+ from .__version__ import VERSION
10
+ from .state import State
11
+
12
+ ArgsParseFuncGenT: typing.TypeAlias = collections.abc.Generator[
13
+ None, tuple[argparse.Namespace, State], None
14
+ ]
15
+ ArgsparseFuncT: typing.TypeAlias = collections.abc.Callable[
16
+ [argparse.ArgumentParser], ArgsParseFuncGenT
17
+ ]
18
+
19
+ registered_functions: list[ArgsparseFuncT] = []
20
+
21
+
22
+ def register_argparser(func: ArgsparseFuncT) -> None:
23
+ """Decorate function to register it to be called when arguments are being parsed."""
24
+ registered_functions.append(func)
25
+
26
+
27
+ def args_parse() -> tuple[tuple[ArgsParseFuncGenT, ...], argparse.Namespace]:
28
+ """Parse passed arguments and return result."""
29
+ parser = argparse.ArgumentParser(prog="shvcli", description="Silicon Heaven CLI")
30
+ parser.add_argument("--version", action="version", version="%(prog)s " + VERSION)
31
+ parser.add_argument(
32
+ "-c",
33
+ "--config",
34
+ action="append",
35
+ type=pathlib.Path,
36
+ default=[pathlib.Path("/etc/shvcli.toml"), pathlib.Path("~/.shvcli.toml")],
37
+ )
38
+ gens = tuple(func(parser) for func in registered_functions)
39
+ for gen in gens:
40
+ next(gen)
41
+ args = parser.parse_args()
42
+ return gens, args
43
+
44
+
45
+ def args_apply(
46
+ gens: tuple[ArgsParseFuncGenT, ...], args: argparse.Namespace, state: State
47
+ ) -> None:
48
+ """Apply parsed arguments on the given state.
49
+
50
+ The parsed arguments should be applied after configuration but
51
+ configuration loading needs to be influenced by arguments and thus split
52
+ arguments parsing to the parsing and application phase.
53
+ """
54
+ for gen in gens:
55
+ with contextlib.suppress(StopIteration):
56
+ gen.send((args, state))
@@ -0,0 +1,86 @@
1
+ """Builtin methods glue code so they can be defined separatelly."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import abc
6
+ import collections.abc
7
+ import inspect
8
+ import typing
9
+
10
+ from prompt_toolkit.completion import Completion
11
+
12
+ from .client import Client
13
+ from .cliitems import CliItems
14
+ from .state import State, StateVar
15
+
16
+
17
+ class Builtin(abc.ABC):
18
+ """The single builtin definition."""
19
+
20
+ builtins: typing.Final[list[type[Builtin]]] = []
21
+
22
+ def __init_subclass__(cls, *args: typing.Any, **kwargs: typing.Any) -> None: # noqa: ANN401
23
+ super().__init_subclass__(*args, **kwargs)
24
+ Builtin.builtins.append(cls)
25
+
26
+ def __init__(self, builtins: Builtins, state: State) -> None:
27
+ self.state = state
28
+
29
+ @property
30
+ @abc.abstractmethod
31
+ def description(self) -> tuple[str, str]:
32
+ """The provider of the description of this builtin.
33
+
34
+ :return: The first string is description of arguments expected by
35
+ builtin and the second one is the builtin description.
36
+ """
37
+
38
+ def completion( # noqa: PLR6301
39
+ self, items: CliItems, client: Client
40
+ ) -> collections.abc.Iterable[Completion]:
41
+ """Parameter completion for this builtin."""
42
+ return tuple()
43
+
44
+ async def completion_async( # noqa: PLR6301
45
+ self, items: CliItems, client: Client
46
+ ) -> collections.abc.AsyncGenerator[Completion, None]:
47
+ """Asynchronous parameter completion for this builtin.
48
+
49
+ This is used only if :class:`AutoProbeOption` is enabled.
50
+
51
+ It is common that this only fetches the required data with client and
52
+ the completion is performed in :meth:`completion` only.
53
+ """
54
+ return
55
+ yield # type: ignore
56
+
57
+ def validate(self, items: CliItems, client: Client) -> None: # noqa: PLR6301
58
+ """Validate the parameter for this builtin."""
59
+ return
60
+
61
+ async def validate_async(self, items: CliItems, client: Client) -> None: # noqa: PLR6301
62
+ """Asynchronously validate the parameter for this builtin.
63
+
64
+ This is used only if :class:`AutoProbeOption` is enabled.
65
+
66
+ It is common that this only fetches the required data with client and
67
+ the validation is performed in :meth:`validate` only. SHVCLI also
68
+ always uses completion and validation together and because completion
69
+ happens alongside with validation it is rather common to do this
70
+ probing in the :meth:`completion_async` only.
71
+ """
72
+ return
73
+
74
+ @abc.abstractmethod
75
+ async def run(self, items: CliItems, client: Client) -> None:
76
+ """Run the builtin."""
77
+
78
+
79
+ class Builtins(StateVar, dict[str, Builtin]):
80
+ """All initialized builtins."""
81
+
82
+ def __init__(self, state: State) -> None:
83
+ super().__init__(state)
84
+ for builtin in Builtin.builtins:
85
+ if not inspect.isabstract(builtin):
86
+ builtin(self, state)
@@ -0,0 +1,27 @@
1
+ """All standard builtins.
2
+
3
+ This module is imported in the top level init and thus all builtins imported
4
+ here are automatically registered.
5
+ """
6
+
7
+ from .broker import BuiltinSubscribe, BuiltinSubscriptions, BuiltinUnsubscribe
8
+ from .cd import BuiltinCD
9
+ from .file import BuiltinDownload, BuiltinUpload, BuiltinVerify
10
+ from .help import BuiltinHelp
11
+ from .scan import BuiltinScan
12
+ from .set import BuiltinSet
13
+ from .tree import BuiltinTree
14
+
15
+ __all__ = [
16
+ "BuiltinCD",
17
+ "BuiltinDownload",
18
+ "BuiltinHelp",
19
+ "BuiltinScan",
20
+ "BuiltinSet",
21
+ "BuiltinSubscribe",
22
+ "BuiltinSubscriptions",
23
+ "BuiltinTree",
24
+ "BuiltinUnsubscribe",
25
+ "BuiltinUpload",
26
+ "BuiltinVerify",
27
+ ]