shvcli 0.4.0__tar.gz → 0.5.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.
- {shvcli-0.4.0/shvcli.egg-info → shvcli-0.5.0}/PKG-INFO +2 -2
- {shvcli-0.4.0 → shvcli-0.5.0}/pyproject.toml +3 -3
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/__version__.py +5 -4
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/builtin.py +7 -2
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/builtin_impl.py +10 -11
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/cli.py +1 -1
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/client.py +13 -16
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/complet.py +2 -1
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/config.py +2 -2
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/parse.py +9 -17
- {shvcli-0.4.0 → shvcli-0.5.0/shvcli.egg-info}/PKG-INFO +2 -2
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli.egg-info/requires.txt +1 -1
- {shvcli-0.4.0 → shvcli-0.5.0}/LICENSE +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/README.rst +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/setup.cfg +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/__init__.py +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/__main__.py +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/complet_tools.py +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/lsdir.py +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/py.typed +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/scan.py +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/tools.py +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/valid.py +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/version +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli.egg-info/SOURCES.txt +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli.egg-info/dependency_links.txt +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli.egg-info/entry_points.txt +0 -0
- {shvcli-0.4.0 → shvcli-0.5.0}/shvcli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: shvcli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Silicon Heaven CLI access application
|
|
5
5
|
Author: Elektroline a.s.
|
|
6
6
|
License: MIT License
|
|
@@ -38,7 +38,7 @@ Classifier: Topic :: Terminals
|
|
|
38
38
|
Requires-Python: >=3.11
|
|
39
39
|
Description-Content-Type: text/x-rst
|
|
40
40
|
License-File: LICENSE
|
|
41
|
-
Requires-Dist: pyshv>=0.
|
|
41
|
+
Requires-Dist: pyshv>=0.7.0
|
|
42
42
|
Requires-Dist: prompt_toolkit
|
|
43
43
|
Requires-Dist: pygments
|
|
44
44
|
Requires-Dist: pyxdg
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "shvcli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
description = "Silicon Heaven CLI access application"
|
|
5
5
|
readme = "README.rst"
|
|
6
6
|
license = {file = "LICENSE"}
|
|
@@ -20,7 +20,7 @@ classifiers = [
|
|
|
20
20
|
]
|
|
21
21
|
requires-python = ">=3.11"
|
|
22
22
|
dependencies = [
|
|
23
|
-
"pyshv >= 0.
|
|
23
|
+
"pyshv >= 0.7.0",
|
|
24
24
|
"prompt_toolkit",
|
|
25
25
|
"pygments",
|
|
26
26
|
"pyxdg",
|
|
@@ -52,7 +52,7 @@ exclude_lines = [
|
|
|
52
52
|
target-version = "py311"
|
|
53
53
|
[tool.ruff.lint]
|
|
54
54
|
select = [
|
|
55
|
-
"F", "E", "W", "I", "N", "D", "UP", "YTT", "ANN", "ASYNC", "
|
|
55
|
+
"F", "E", "W", "I", "N", "D", "UP", "YTT", "ANN", "ASYNC", "ASYNC1", "S", "BLE",
|
|
56
56
|
"B", "A", "COM", "PL", "RUF"
|
|
57
57
|
]
|
|
58
58
|
ignore = [
|
|
@@ -15,10 +15,11 @@ def _get_version() -> str:
|
|
|
15
15
|
if str(dist.locate_file(f"{__package__}/__version__.py")) == __file__:
|
|
16
16
|
return dist.version
|
|
17
17
|
pyproject = pathlib.Path(__file__).parent.parent / "pyproject.toml"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
if pyproject.exists():
|
|
19
|
+
with pyproject.open("rb") as f:
|
|
20
|
+
res = tomllib.load(f)["project"]["version"]
|
|
21
|
+
if isinstance(res, str):
|
|
22
|
+
return res
|
|
22
23
|
return "unknown"
|
|
23
24
|
|
|
24
25
|
|
|
@@ -10,7 +10,9 @@ from .client import SHVClient
|
|
|
10
10
|
from .config import CliConfig
|
|
11
11
|
from .parse import CliItems
|
|
12
12
|
|
|
13
|
-
_T_METHOD = typing.Callable[
|
|
13
|
+
_T_METHOD = typing.Callable[
|
|
14
|
+
[SHVClient, CliConfig, CliItems], typing.Awaitable[None] | None
|
|
15
|
+
]
|
|
14
16
|
_T_XMETHOD = typing.Callable[
|
|
15
17
|
[SHVClient, CliConfig, CliItems, int | None], typing.Awaitable[None]
|
|
16
18
|
]
|
|
@@ -115,7 +117,10 @@ async def call_builtin(
|
|
|
115
117
|
return
|
|
116
118
|
|
|
117
119
|
if isinstance(m, Method):
|
|
118
|
-
|
|
120
|
+
res = m.func(shvclient, config, items)
|
|
121
|
+
if isinstance(res, collections.abc.Awaitable):
|
|
122
|
+
await res
|
|
123
|
+
return
|
|
119
124
|
|
|
120
125
|
typing.assert_type(m, XMethod)
|
|
121
126
|
strnum = items.method[len(m.name) + 1 :]
|
|
@@ -5,7 +5,6 @@ import inspect
|
|
|
5
5
|
import itertools
|
|
6
6
|
|
|
7
7
|
from prompt_toolkit.completion import Completion
|
|
8
|
-
from shv import RpcSubscription
|
|
9
8
|
|
|
10
9
|
from .builtin import METHODS, Argument, XMethod, builtin, xbuiltin
|
|
11
10
|
from .client import Node, SHVClient
|
|
@@ -22,11 +21,13 @@ def argument_signal_comp(
|
|
|
22
21
|
) -> collections.abc.Iterable[Completion]:
|
|
23
22
|
"""Completion for subscribe argument."""
|
|
24
23
|
if ":" in items.param_raw:
|
|
25
|
-
path, method = items.
|
|
26
|
-
assert method is not None
|
|
24
|
+
path, method, signal = items.interpret_param_ri(config).split(":")
|
|
27
25
|
node = shvclient.tree.get_path(path)
|
|
28
26
|
if node is not None:
|
|
29
|
-
|
|
27
|
+
if items.param_raw.count(":") == 1:
|
|
28
|
+
yield from comp_from(method, node.methods)
|
|
29
|
+
elif method in node.methods:
|
|
30
|
+
yield from comp_from(signal, node.methods[method])
|
|
30
31
|
else:
|
|
31
32
|
yield from comp_path(shvclient, config, items)
|
|
32
33
|
|
|
@@ -53,7 +54,7 @@ argument_set = Argument("[OPTION [VALUE]]", argument_set_comp)
|
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
@builtin("help", {"h"}, hidden=True)
|
|
56
|
-
|
|
57
|
+
def _help(_: SHVClient, __: CliConfig, ___: CliItems) -> None:
|
|
57
58
|
"""Print help for all builtin methods."""
|
|
58
59
|
print_row("Available internal methods (all prefixed with '!'):")
|
|
59
60
|
for name, m in METHODS.items():
|
|
@@ -70,15 +71,13 @@ async def _help(_: SHVClient, __: CliConfig, ___: CliItems) -> None:
|
|
|
70
71
|
@builtin(aliases={"sub"}, argument=argument_signal)
|
|
71
72
|
async def subscribe(shvclient: SHVClient, config: CliConfig, items: CliItems) -> None:
|
|
72
73
|
"""Add new subscribe."""
|
|
73
|
-
|
|
74
|
-
await shvclient.subscribe(RpcSubscription(path, method or ""))
|
|
74
|
+
await shvclient.subscribe(items.interpret_param_ri(config))
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
@builtin(aliases={"usub"}, argument=argument_signal)
|
|
78
78
|
async def unsubscribe(shvclient: SHVClient, config: CliConfig, items: CliItems) -> None:
|
|
79
79
|
"""Unsubscribe existing subscription."""
|
|
80
|
-
|
|
81
|
-
await shvclient.unsubscribe(RpcSubscription(path, method or ""))
|
|
80
|
+
await shvclient.unsubscribe(items.interpret_param_ri(config))
|
|
82
81
|
|
|
83
82
|
|
|
84
83
|
@builtin(aliases={"subs", "test"})
|
|
@@ -88,7 +87,7 @@ async def subscriptions(shvclient: SHVClient, _: CliConfig, __: CliItems) -> Non
|
|
|
88
87
|
|
|
89
88
|
|
|
90
89
|
@builtin(aliases={"t"}, argument=argument_path)
|
|
91
|
-
|
|
90
|
+
def tree(shvclient: SHVClient, config: CliConfig, items: CliItems) -> None:
|
|
92
91
|
"""Print tree of nodes discovered in this session."""
|
|
93
92
|
|
|
94
93
|
def print_node(node: Node, cols: list[bool]) -> None:
|
|
@@ -126,7 +125,7 @@ async def scan(
|
|
|
126
125
|
|
|
127
126
|
|
|
128
127
|
@builtin("set", aliases={"s"}, argument=argument_set)
|
|
129
|
-
|
|
128
|
+
def _set(_: SHVClient, config: CliConfig, items: CliItems) -> None:
|
|
130
129
|
"""Set configuration options in runtime."""
|
|
131
130
|
opt, val = items.interpret_param_set()
|
|
132
131
|
if not opt:
|
|
@@ -52,7 +52,7 @@ async def _app(config: CliConfig, shvclient: SHVClient) -> None:
|
|
|
52
52
|
[prompt_path, ("", "> ")], vi_mode=config.vimode
|
|
53
53
|
)
|
|
54
54
|
except EOFError:
|
|
55
|
-
shvclient.
|
|
55
|
+
await shvclient.disconnect()
|
|
56
56
|
return
|
|
57
57
|
await handle_line(shvclient, config, result)
|
|
58
58
|
except KeyboardInterrupt:
|
|
@@ -26,8 +26,7 @@ class Node(collections.abc.Mapping[str, "Node"]):
|
|
|
26
26
|
def __init__(self) -> None:
|
|
27
27
|
"""Initialize the node."""
|
|
28
28
|
self.nodes: dict[str, Node] = {}
|
|
29
|
-
self.methods: set[str] = {"ls", "dir"}
|
|
30
|
-
self.signals: set[str] = set()
|
|
29
|
+
self.methods: dict[str, set[str]] = {"ls": {"lsmod"}, "dir": set()}
|
|
31
30
|
self.nodes_probed = False
|
|
32
31
|
self.methods_probed = False
|
|
33
32
|
|
|
@@ -83,8 +82,7 @@ class Node(collections.abc.Mapping[str, "Node"]):
|
|
|
83
82
|
"""Dump the data to basic types."""
|
|
84
83
|
return {
|
|
85
84
|
"nodes": {n: v.dump() for n, v in self.nodes.items()},
|
|
86
|
-
"methods": list(self.methods),
|
|
87
|
-
"signals": list(self.signals),
|
|
85
|
+
"methods": {n: list(v) for n, v in self.methods.items()},
|
|
88
86
|
"nodes_probed": self.nodes_probed,
|
|
89
87
|
"methods_probed": self.methods_probed,
|
|
90
88
|
}
|
|
@@ -96,10 +94,8 @@ class Node(collections.abc.Mapping[str, "Node"]):
|
|
|
96
94
|
res = cls()
|
|
97
95
|
if isinstance(data["nodes"], collections.abc.Mapping):
|
|
98
96
|
res.nodes = {n: cls.load(v) for n, v in data["nodes"].items()}
|
|
99
|
-
if isinstance(data["methods"], collections.abc.
|
|
100
|
-
res.methods = set(data["methods"])
|
|
101
|
-
if isinstance(data["signals"], collections.abc.Sequence):
|
|
102
|
-
res.signals = set(data["signals"])
|
|
97
|
+
if isinstance(data["methods"], collections.abc.Mapping):
|
|
98
|
+
res.methods = {str(n): set(v) for n, v in data["methods"].items()}
|
|
103
99
|
res.nodes_probed = bool(data["nodes_probed"])
|
|
104
100
|
res.methods_probed = bool(data["methods_probed"])
|
|
105
101
|
return res
|
|
@@ -124,10 +120,10 @@ class SHVClient(SimpleClient):
|
|
|
124
120
|
async def _message(self, msg: RpcMessage) -> None:
|
|
125
121
|
await super()._message(msg)
|
|
126
122
|
if msg.is_signal:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
print(f"{msg.path}:{
|
|
123
|
+
self.tree.valid_path(msg.path or "").methods.setdefault(
|
|
124
|
+
msg.source, set()
|
|
125
|
+
).add(msg.signal_name)
|
|
126
|
+
print(f"{msg.path}:{msg.source}:{msg.signal_name}: {Cpon.pack(msg.param)}")
|
|
131
127
|
|
|
132
128
|
async def ls(self, path: str) -> list[str]:
|
|
133
129
|
"""List same as in ValueClient but with result being preserved in tree."""
|
|
@@ -154,9 +150,10 @@ class SHVClient(SimpleClient):
|
|
|
154
150
|
raise exc
|
|
155
151
|
node = self.tree.valid_path(path)
|
|
156
152
|
node.methods = {
|
|
157
|
-
d.name
|
|
153
|
+
d.name: set(d.signals)
|
|
154
|
+
for d in res
|
|
155
|
+
if RpcMethodFlags.NOT_CALLABLE not in d.flags
|
|
158
156
|
}
|
|
159
|
-
node.signals = {d.name for d in res if RpcMethodFlags.NOT_CALLABLE in d.flags}
|
|
160
157
|
node.methods_probed = True
|
|
161
158
|
return res
|
|
162
159
|
|
|
@@ -177,9 +174,9 @@ class SHVClient(SimpleClient):
|
|
|
177
174
|
except RpcMethodNotFoundError as exc:
|
|
178
175
|
raise exc
|
|
179
176
|
except RpcError as exc:
|
|
180
|
-
self.tree.valid_path(path).methods.
|
|
177
|
+
self.tree.valid_path(path).methods.setdefault(method, set())
|
|
181
178
|
raise exc
|
|
182
|
-
self.tree.valid_path(path).methods.
|
|
179
|
+
self.tree.valid_path(path).methods.setdefault(method, set())
|
|
183
180
|
return res
|
|
184
181
|
|
|
185
182
|
async def probe(self, path: str) -> Node | None:
|
|
@@ -61,7 +61,8 @@ class CliCompleter(Completer):
|
|
|
61
61
|
CliFlags.COMPLETE_CALL not in items.flags
|
|
62
62
|
or items.method in {"ls", "dir"}
|
|
63
63
|
or (
|
|
64
|
-
items.method
|
|
64
|
+
items.method
|
|
65
|
+
and items.method[0] == "!"
|
|
65
66
|
and (bmethod := builtin.get_builtin(items.method[1:])) is not None
|
|
66
67
|
and bmethod.argument
|
|
67
68
|
and bmethod.argument.autoprobe
|
|
@@ -101,9 +101,9 @@ class CliConfig:
|
|
|
101
101
|
self.__rurl = self.__url
|
|
102
102
|
elif isinstance(self.__url, str):
|
|
103
103
|
self.__rurl = RpcUrl.parse(
|
|
104
|
-
subprocess.run(
|
|
104
|
+
subprocess.run( # noqa S602
|
|
105
105
|
f"printf '%s' \"{self.__url}\"",
|
|
106
|
-
shell=True,
|
|
106
|
+
shell=True,
|
|
107
107
|
stdout=subprocess.PIPE,
|
|
108
108
|
check=True,
|
|
109
109
|
).stdout.decode()
|
|
@@ -39,16 +39,6 @@ class CliItems:
|
|
|
39
39
|
return None
|
|
40
40
|
return Cpon.unpack(self.param_raw)
|
|
41
41
|
|
|
42
|
-
@property
|
|
43
|
-
def param_method(self) -> tuple[str, str | None]:
|
|
44
|
-
"""Interpret parameter as path and method."""
|
|
45
|
-
if ":" in self.param_raw:
|
|
46
|
-
path, method = self.param_raw.split(":", maxsplit=1)
|
|
47
|
-
return path, method
|
|
48
|
-
if "/" in self.param_raw:
|
|
49
|
-
return self.param_raw, None
|
|
50
|
-
return "", self.param_raw
|
|
51
|
-
|
|
52
42
|
def interpret_param_path(self, config: CliConfig) -> str:
|
|
53
43
|
"""Interpret parameter as path specification.
|
|
54
44
|
|
|
@@ -56,16 +46,18 @@ class CliItems:
|
|
|
56
46
|
"""
|
|
57
47
|
return config.shvpath([self.path, self.param_raw])
|
|
58
48
|
|
|
59
|
-
def
|
|
60
|
-
"""Interpret parameter as
|
|
49
|
+
def interpret_param_ri(self, config: CliConfig, expand: bool = True) -> str:
|
|
50
|
+
"""Interpret parameter as RI.
|
|
61
51
|
|
|
62
|
-
|
|
63
|
-
path and method not just parsed :prop:`param_raw`.
|
|
52
|
+
The path in RI is combined with pat in the configuration.
|
|
64
53
|
|
|
65
|
-
:return:
|
|
54
|
+
:return: SHV RPC RI.
|
|
66
55
|
"""
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
parts = self.param_raw.split(":")
|
|
57
|
+
path = parts[0] if parts[0] else "**"
|
|
58
|
+
method = parts[1] if len(parts) == 2 else "*"
|
|
59
|
+
signal = parts[2] if len(parts) == 3 else "*"
|
|
60
|
+
return f"{self.path}{"/" if path else ""}{path}:{method}:{signal}"
|
|
69
61
|
|
|
70
62
|
def interpret_param_set(self) -> tuple[str | None, str | None]:
|
|
71
63
|
"""Interpret parameter as 'set' method specification.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: shvcli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Silicon Heaven CLI access application
|
|
5
5
|
Author: Elektroline a.s.
|
|
6
6
|
License: MIT License
|
|
@@ -38,7 +38,7 @@ Classifier: Topic :: Terminals
|
|
|
38
38
|
Requires-Python: >=3.11
|
|
39
39
|
Description-Content-Type: text/x-rst
|
|
40
40
|
License-File: LICENSE
|
|
41
|
-
Requires-Dist: pyshv>=0.
|
|
41
|
+
Requires-Dist: pyshv>=0.7.0
|
|
42
42
|
Requires-Dist: prompt_toolkit
|
|
43
43
|
Requires-Dist: pygments
|
|
44
44
|
Requires-Dist: pyxdg
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|