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.
Files changed (28) hide show
  1. {shvcli-0.4.0/shvcli.egg-info → shvcli-0.5.0}/PKG-INFO +2 -2
  2. {shvcli-0.4.0 → shvcli-0.5.0}/pyproject.toml +3 -3
  3. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/__version__.py +5 -4
  4. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/builtin.py +7 -2
  5. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/builtin_impl.py +10 -11
  6. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/cli.py +1 -1
  7. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/client.py +13 -16
  8. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/complet.py +2 -1
  9. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/config.py +2 -2
  10. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/parse.py +9 -17
  11. {shvcli-0.4.0 → shvcli-0.5.0/shvcli.egg-info}/PKG-INFO +2 -2
  12. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli.egg-info/requires.txt +1 -1
  13. {shvcli-0.4.0 → shvcli-0.5.0}/LICENSE +0 -0
  14. {shvcli-0.4.0 → shvcli-0.5.0}/README.rst +0 -0
  15. {shvcli-0.4.0 → shvcli-0.5.0}/setup.cfg +0 -0
  16. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/__init__.py +0 -0
  17. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/__main__.py +0 -0
  18. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/complet_tools.py +0 -0
  19. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/lsdir.py +0 -0
  20. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/py.typed +0 -0
  21. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/scan.py +0 -0
  22. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/tools.py +0 -0
  23. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/valid.py +0 -0
  24. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli/version +0 -0
  25. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli.egg-info/SOURCES.txt +0 -0
  26. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli.egg-info/dependency_links.txt +0 -0
  27. {shvcli-0.4.0 → shvcli-0.5.0}/shvcli.egg-info/entry_points.txt +0 -0
  28. {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.4.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.6.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.4.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.6.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", "TRIO", "S", "BLE",
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
- with pyproject.open("rb") as f:
19
- res = tomllib.load(f)["project"]["version"]
20
- if isinstance(res, str):
21
- return res
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[[SHVClient, CliConfig, CliItems], typing.Awaitable[None]]
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
- return await m.func(shvclient, config, items)
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.interpret_param_method(config)
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
- yield from comp_from(method, node.signals)
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
- async def _help(_: SHVClient, __: CliConfig, ___: CliItems) -> None:
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
- path, method = items.interpret_param_method(config)
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
- path, method = items.interpret_param_method(config)
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
- async def tree(shvclient: SHVClient, config: CliConfig, items: CliItems) -> None:
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
- async def _set(_: SHVClient, config: CliConfig, items: CliItems) -> None:
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.client.disconnect()
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.Sequence):
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
- method = msg.method
128
- assert method is not None
129
- self.tree.valid_path(msg.path or "").signals.add(method)
130
- print(f"{msg.path}:{method}: {Cpon.pack(msg.param)}")
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 for d in res if RpcMethodFlags.NOT_CALLABLE not in d.flags
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.add(method)
177
+ self.tree.valid_path(path).methods.setdefault(method, set())
181
178
  raise exc
182
- self.tree.valid_path(path).methods.add(method)
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[0] == "!"
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, # noqa S602
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 interpret_param_method(self, config: CliConfig) -> tuple[str, str | None]:
60
- """Interpret parameter as method specification.
49
+ def interpret_param_ri(self, config: CliConfig, expand: bool = True) -> str:
50
+ """Interpret parameter as RI.
61
51
 
62
- Compared to :meth:`param_method` this provides a full combination of
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: pair of SHV path and method name that is from parameter.
54
+ :return: SHV RPC RI.
66
55
  """
67
- param_path, method = self.param_method
68
- return config.shvpath([self.path, param_path]), method
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.4.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.6.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,4 +1,4 @@
1
- pyshv>=0.6.0
1
+ pyshv>=0.7.0
2
2
  prompt_toolkit
3
3
  pygments
4
4
  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