shvcli 0.6.1__tar.gz → 0.6.2__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 (29) hide show
  1. {shvcli-0.6.1/shvcli.egg-info → shvcli-0.6.2}/PKG-INFO +9 -12
  2. {shvcli-0.6.1 → shvcli-0.6.2}/README.rst +6 -9
  3. {shvcli-0.6.1 → shvcli-0.6.2}/pyproject.toml +2 -4
  4. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/builtin_impl.py +50 -27
  5. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/cli.py +16 -14
  6. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/client.py +3 -3
  7. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/parse.py +0 -8
  8. shvcli-0.6.2/shvcli/plugins.py +18 -0
  9. {shvcli-0.6.1 → shvcli-0.6.2/shvcli.egg-info}/PKG-INFO +9 -12
  10. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli.egg-info/SOURCES.txt +1 -1
  11. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli.egg-info/requires.txt +1 -1
  12. shvcli-0.6.1/shvcli/version +0 -1
  13. {shvcli-0.6.1 → shvcli-0.6.2}/LICENSE +0 -0
  14. {shvcli-0.6.1 → shvcli-0.6.2}/setup.cfg +0 -0
  15. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/__init__.py +0 -0
  16. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/__main__.py +0 -0
  17. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/__version__.py +0 -0
  18. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/builtin.py +0 -0
  19. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/complet.py +0 -0
  20. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/complet_tools.py +0 -0
  21. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/config.py +0 -0
  22. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/lsdir.py +0 -0
  23. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/py.typed +0 -0
  24. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/scan.py +0 -0
  25. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/tools.py +0 -0
  26. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli/valid.py +0 -0
  27. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli.egg-info/dependency_links.txt +0 -0
  28. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli.egg-info/entry_points.txt +0 -0
  29. {shvcli-0.6.1 → shvcli-0.6.2}/shvcli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: shvcli
3
- Version: 0.6.1
3
+ Version: 0.6.2
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.7.1
41
+ Requires-Dist: pyshv>=0.8.0
42
42
  Requires-Dist: prompt_toolkit
43
43
  Requires-Dist: pygments
44
44
  Requires-Dist: pyxdg
@@ -172,10 +172,7 @@ environment you are running in.
172
172
 
173
173
  **subscribe|sub**: Add new subscribe. Shortcut to the call of
174
174
  ``.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.
175
+ way. The argument can be multiple RPC RIs (``PATH:METHOD:SIGNAL`` patterns).
179
176
 
180
177
  **unsubscribe|usub**: Unsubscribe existing subscription. It is reverse operation
181
178
  to the **subscribe** and same remarks apply here as well. It is a shortcut to
@@ -197,11 +194,11 @@ cache.
197
194
  thus use it sparely.
198
195
 
199
196
  **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.
197
+ are the same as in ``config`` section. The boolean options are set if no
198
+ argument is provided, or cleared if name is prefixed with ``no`` (and thus to
199
+ disable ``raw`` you use ``noraw``). You can also add ``=true`` or ``=false``.
200
+ The equal sign is also used with integer and floating point options. Without any
201
+ configuration option it simply prints the current configuration.
205
202
 
206
203
 
207
204
  Special methods ``ls`` and ``dir``
@@ -127,10 +127,7 @@ environment you are running in.
127
127
 
128
128
  **subscribe|sub**: Add new subscribe. Shortcut to the call of
129
129
  ``.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.
130
+ way. The argument can be multiple RPC RIs (``PATH:METHOD:SIGNAL`` patterns).
134
131
 
135
132
  **unsubscribe|usub**: Unsubscribe existing subscription. It is reverse operation
136
133
  to the **subscribe** and same remarks apply here as well. It is a shortcut to
@@ -152,11 +149,11 @@ cache.
152
149
  thus use it sparely.
153
150
 
154
151
  **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.
152
+ are the same as in ``config`` section. The boolean options are set if no
153
+ argument is provided, or cleared if name is prefixed with ``no`` (and thus to
154
+ disable ``raw`` you use ``noraw``). You can also add ``=true`` or ``=false``.
155
+ The equal sign is also used with integer and floating point options. Without any
156
+ configuration option it simply prints the current configuration.
160
157
 
161
158
 
162
159
  Special methods ``ls`` and ``dir``
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "shvcli"
3
- version = "0.6.1"
3
+ version = "0.6.2"
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.7.1",
23
+ "pyshv >= 0.8.0",
24
24
  "prompt_toolkit",
25
25
  "pygments",
26
26
  "pyxdg",
@@ -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]
@@ -33,19 +33,27 @@ def argument_signal_comp(
33
33
 
34
34
 
35
35
  def argument_set_comp(
36
- _: SHVClient, config: CliConfig, items: CliItems
36
+ client: SHVClient, config: CliConfig, items: CliItems
37
37
  ) -> collections.abc.Iterable[Completion]:
38
38
  """Completion for !set method."""
39
- opt, val = items.interpret_param_set()
40
- if val is not None:
41
- if config.OPTS.get(opt or "") is config.Type.BOOL:
39
+ item = items.param_raw.split()[-1] if items.param_raw else ""
40
+ if "=" in item:
41
+ opt, _, val = item.partition("=")
42
+ if config.OPTS.get(opt) == config.Type.BOOL:
42
43
  yield from comp_from(val, {"true", "false"})
43
44
  else:
44
- yield from comp_from(items.param_raw, config.OPTS.keys())
45
45
  yield from comp_from(
46
- items.param_raw,
46
+ item,
47
+ (v for v, t in config.OPTS.items() if t is config.Type.BOOL),
48
+ )
49
+ yield from comp_from(
50
+ item,
47
51
  (f"no{v}" for v, t in config.OPTS.items() if t is config.Type.BOOL),
48
52
  )
53
+ yield from comp_from(
54
+ item,
55
+ (f"{v}=" for v, t in config.OPTS.items() if t is not config.Type.BOOL),
56
+ )
49
57
 
50
58
 
51
59
  argument_signal = Argument("[PATH:SIGNAL]", argument_signal_comp, autoprobe=True)
@@ -54,7 +62,7 @@ argument_set = Argument("[OPTION [VALUE]]", argument_set_comp)
54
62
 
55
63
 
56
64
  @builtin("help", {"h"}, hidden=True)
57
- def _help(_: SHVClient, __: CliConfig, ___: CliItems) -> None:
65
+ def _help(client: SHVClient, config: CliConfig, items: CliItems) -> None:
58
66
  """Print help for all builtin methods."""
59
67
  print_row("Available internal methods (all prefixed with '!'):")
60
68
  for name, m in METHODS.items():
@@ -83,7 +91,9 @@ async def unsubscribe(shvclient: SHVClient, config: CliConfig, items: CliItems)
83
91
 
84
92
 
85
93
  @builtin(aliases={"subs", "test"})
86
- async def subscriptions(shvclient: SHVClient, _: CliConfig, __: CliItems) -> None:
94
+ async def subscriptions(
95
+ shvclient: SHVClient, config: CliConfig, items: CliItems
96
+ ) -> None:
87
97
  """List current subscriptions."""
88
98
  subs = await shvclient.call(".broker/currentClient", "subscriptions")
89
99
  if isinstance(subs, dict):
@@ -118,7 +128,7 @@ def tree(shvclient: SHVClient, config: CliConfig, items: CliItems) -> None:
118
128
 
119
129
 
120
130
  @builtin(argument=argument_path)
121
- async def cd(_: SHVClient, __: CliConfig, ___: CliItems) -> None:
131
+ async def cd(client: SHVClient, config: CliConfig, itemst: CliItems) -> None:
122
132
  """Change to given path even if it is invalid."""
123
133
 
124
134
 
@@ -134,10 +144,9 @@ async def scan(
134
144
 
135
145
 
136
146
  @builtin("set", aliases={"s"}, argument=argument_set)
137
- def _set(_: SHVClient, config: CliConfig, items: CliItems) -> None:
147
+ def _set(client: SHVClient, config: CliConfig, items: CliItems) -> None:
138
148
  """Set configuration options in runtime."""
139
- opt, val = items.interpret_param_set()
140
- if not opt:
149
+ if not items.param_raw.strip():
141
150
  w = max(len(n) for n in config.OPTS.keys())
142
151
  for n, t in config.OPTS.items():
143
152
  row = [("", (" " * (w - len(n))) + n + " ")]
@@ -146,25 +155,39 @@ def _set(_: SHVClient, config: CliConfig, items: CliItems) -> None:
146
155
  v = getattr(config, n)
147
156
  assert isinstance(v, bool)
148
157
  row.append(("ansigreen" if v else "ansired", str(v).lower()))
149
- case config.Type.INT:
158
+ case config.Type.INT | config.Type.FLOAT:
150
159
  row.append(("", str(getattr(config, n))))
151
160
  case _:
152
161
  raise NotImplementedError(f"Unimplemented {t!r}")
153
162
  print_row(row)
154
163
  return
155
164
 
156
- # TODO from here we need add support for integers when we need it.
157
- if no := opt.startswith("no"):
158
- opt = opt[2:]
159
- if opt not in config.OPTS.keys():
160
- print(f"Invalid option: {opt}")
161
- return
162
- if val is None:
163
- value = not no
164
- else:
165
- m = {"true": True, "t": True, "false": False, "f": False}
166
- if val not in m:
167
- print(f"Invalid value, expected 'true' or 'false': {val}")
165
+ for opt in items.param_raw.split():
166
+ if "=" in opt:
167
+ opt, _, val = opt.partition("=") # noqa: PLW2901
168
+ if opt not in config.OPTS.keys():
169
+ print(f"Invalid option: {opt}")
170
+ return
171
+ value: bool | int | float
172
+ match config.OPTS[opt]:
173
+ case config.Type.BOOL:
174
+ bools = {"true": True, "t": True, "false": False, "f": False}
175
+ if val not in bools:
176
+ print(f"Invalid value, expected 'true' or 'false': {val}")
177
+ return
178
+ value = bools[val]
179
+ case config.Type.INT:
180
+ value = int(val, 0)
181
+ case config.Type.FLOAT:
182
+ value = float(val)
183
+ case _:
184
+ raise NotImplementedError(f"Unimplemented {t!r}")
185
+ setattr(config, opt, value)
186
+ continue
187
+
188
+ if no := opt.startswith("no"):
189
+ opt = opt[2:] # noqa: PLW2901
190
+ if opt not in config.OPTS.keys():
191
+ print(f"Invalid option: {opt}")
168
192
  return
169
- value = m[val]
170
- setattr(config, opt, value)
193
+ setattr(config, opt, not no)
@@ -1,6 +1,7 @@
1
1
  """Command line interface."""
2
2
 
3
3
  import asyncio
4
+ import contextlib
4
5
  import json
5
6
  import pathlib
6
7
  import re
@@ -30,13 +31,10 @@ async def _app(config: CliConfig, shvclient: SHVClient) -> None:
30
31
  with histfile.open("w") as _:
31
32
  pass
32
33
 
33
- completer = CliCompleter(shvclient, config)
34
- validator = CliValidator(shvclient, config)
35
-
36
34
  session: PromptSession = PromptSession(
37
35
  history=FileHistory(str(histfile)),
38
- completer=completer,
39
- validator=validator,
36
+ completer=CliCompleter(shvclient, config),
37
+ validator=CliValidator(shvclient, config),
40
38
  )
41
39
  while True:
42
40
  try:
@@ -52,7 +50,6 @@ async def _app(config: CliConfig, shvclient: SHVClient) -> None:
52
50
  [prompt_path, ("", "> ")], vi_mode=config.vimode
53
51
  )
54
52
  except EOFError:
55
- await shvclient.disconnect()
56
53
  return
57
54
  await handle_line(shvclient, config, result)
58
55
  except KeyboardInterrupt:
@@ -82,15 +79,20 @@ async def run(config: CliConfig, subscriptions: list[str]) -> None:
82
79
  if config.initial_scan:
83
80
  await scan_nodes(shvclient, "", config.initial_scan_depth)
84
81
 
85
- clitask = asyncio.create_task(_app(config, shvclient))
86
- await shvclient.client.wait_disconnect()
87
- if not clitask.done():
82
+ app_task = asyncio.create_task(_app(config, shvclient))
83
+ disconnect_task = asyncio.create_task(shvclient.client.wait_disconnect())
84
+ tasks: set[asyncio.Task] = {app_task, disconnect_task}
85
+ await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
86
+
87
+ if not app_task.done():
88
+ app_task.cancel()
89
+ if disconnect_task.done():
88
90
  print("Disconnected.")
89
- clitask.cancel()
90
- try:
91
- await clitask
92
- except asyncio.CancelledError:
93
- pass
91
+ else:
92
+ await shvclient.disconnect()
93
+ await disconnect_task
94
+ with contextlib.suppress(asyncio.CancelledError):
95
+ await app_task
94
96
 
95
97
  if config.cache:
96
98
  cachepath.parent.mkdir(exist_ok=True)
@@ -13,8 +13,8 @@ from shv import (
13
13
  RpcMethodFlags,
14
14
  RpcMethodNotFoundError,
15
15
  SHVType,
16
- SimpleClient,
17
16
  )
17
+ from shv import SHVClient as _SHVClient
18
18
 
19
19
  from . import VERSION
20
20
  from .tools import print_cpon
@@ -67,7 +67,7 @@ class Node(collections.abc.Mapping[str, "Node"]):
67
67
  if pnode is not None:
68
68
  pnode.nodes.pop(path.name)
69
69
 
70
- def get_path(self, path: str | PurePosixPath) -> None | Node:
70
+ def get_path(self, path: str | PurePosixPath) -> Node | None:
71
71
  """Get node on given path."""
72
72
  if isinstance(path, str):
73
73
  path = PurePosixPath(path)
@@ -101,7 +101,7 @@ class Node(collections.abc.Mapping[str, "Node"]):
101
101
  return res
102
102
 
103
103
 
104
- class SHVClient(SimpleClient):
104
+ class SHVClient(_SHVClient):
105
105
  """Our client caching SHV Tree and reporting received signals."""
106
106
 
107
107
  APP_NAME = "shvcli"
@@ -62,14 +62,6 @@ class CliItems:
62
62
  res.append(f"{self.path}{'/' if self.path else ''}{path}:{method}:{signal}")
63
63
  return res
64
64
 
65
- def interpret_param_set(self) -> tuple[str | None, str | None]:
66
- """Interpret parameter as 'set' method specification.
67
-
68
- :return: First word and rest of the string.
69
- """
70
- s = self.param_raw.split(" ", maxsplit=1)
71
- return s[0] if s else None, s[1] if len(s) > 1 else None
72
-
73
65
 
74
66
  def parse_line(line: str) -> CliItems:
75
67
  """Parse CLI line."""
@@ -0,0 +1,18 @@
1
+ """Utility to manage plugins."""
2
+
3
+ import importlib
4
+ import importlib.metadata
5
+ import logging
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ def load_plugins() -> None:
11
+ """Import plugins.
12
+
13
+ Plugins get inserted automatically. We have to only ensure that we import
14
+ them.
15
+ """
16
+ for plugin in importlib.metadata.entry_points(group="shvcli.plugins"):
17
+ logger.debug("Loading plugin: %s", plugin.name)
18
+ importlib.__import__(plugin.value)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: shvcli
3
- Version: 0.6.1
3
+ Version: 0.6.2
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.7.1
41
+ Requires-Dist: pyshv>=0.8.0
42
42
  Requires-Dist: prompt_toolkit
43
43
  Requires-Dist: pygments
44
44
  Requires-Dist: pyxdg
@@ -172,10 +172,7 @@ environment you are running in.
172
172
 
173
173
  **subscribe|sub**: Add new subscribe. Shortcut to the call of
174
174
  ``.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.
175
+ way. The argument can be multiple RPC RIs (``PATH:METHOD:SIGNAL`` patterns).
179
176
 
180
177
  **unsubscribe|usub**: Unsubscribe existing subscription. It is reverse operation
181
178
  to the **subscribe** and same remarks apply here as well. It is a shortcut to
@@ -197,11 +194,11 @@ cache.
197
194
  thus use it sparely.
198
195
 
199
196
  **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.
197
+ are the same as in ``config`` section. The boolean options are set if no
198
+ argument is provided, or cleared if name is prefixed with ``no`` (and thus to
199
+ disable ``raw`` you use ``noraw``). You can also add ``=true`` or ``=false``.
200
+ The equal sign is also used with integer and floating point options. Without any
201
+ configuration option it simply prints the current configuration.
205
202
 
206
203
 
207
204
  Special methods ``ls`` and ``dir``
@@ -13,11 +13,11 @@ shvcli/complet_tools.py
13
13
  shvcli/config.py
14
14
  shvcli/lsdir.py
15
15
  shvcli/parse.py
16
+ shvcli/plugins.py
16
17
  shvcli/py.typed
17
18
  shvcli/scan.py
18
19
  shvcli/tools.py
19
20
  shvcli/valid.py
20
- shvcli/version
21
21
  shvcli.egg-info/PKG-INFO
22
22
  shvcli.egg-info/SOURCES.txt
23
23
  shvcli.egg-info/dependency_links.txt
@@ -1,4 +1,4 @@
1
- pyshv>=0.7.1
1
+ pyshv>=0.8.0
2
2
  prompt_toolkit
3
3
  pygments
4
4
  pyxdg
@@ -1 +0,0 @@
1
- 0.3.0
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