shvcli 0.6.0__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.0/shvcli.egg-info → shvcli-0.6.2}/PKG-INFO +15 -12
  2. {shvcli-0.6.0 → shvcli-0.6.2}/README.rst +12 -9
  3. {shvcli-0.6.0 → shvcli-0.6.2}/pyproject.toml +2 -4
  4. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/builtin_impl.py +50 -27
  5. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/cli.py +23 -15
  6. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/client.py +3 -3
  7. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/config.py +25 -5
  8. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/lsdir.py +12 -4
  9. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/parse.py +1 -9
  10. shvcli-0.6.2/shvcli/plugins.py +18 -0
  11. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/tools.py +1 -1
  12. {shvcli-0.6.0 → shvcli-0.6.2/shvcli.egg-info}/PKG-INFO +15 -12
  13. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli.egg-info/SOURCES.txt +1 -1
  14. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli.egg-info/requires.txt +1 -1
  15. shvcli-0.6.0/shvcli/version +0 -1
  16. {shvcli-0.6.0 → shvcli-0.6.2}/LICENSE +0 -0
  17. {shvcli-0.6.0 → shvcli-0.6.2}/setup.cfg +0 -0
  18. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/__init__.py +0 -0
  19. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/__main__.py +0 -0
  20. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/__version__.py +0 -0
  21. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/builtin.py +0 -0
  22. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/complet.py +0 -0
  23. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/complet_tools.py +0 -0
  24. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/py.typed +0 -0
  25. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/scan.py +0 -0
  26. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli/valid.py +0 -0
  27. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli.egg-info/dependency_links.txt +0 -0
  28. {shvcli-0.6.0 → shvcli-0.6.2}/shvcli.egg-info/entry_points.txt +0 -0
  29. {shvcli-0.6.0 → 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.0
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
@@ -140,6 +140,12 @@ switched in runtime. The following options are available:
140
140
  * **cache**: Controls if cache is preserved between invocations. Cache is
141
141
  separated based on the connection URL and stored in files in
142
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
148
+ functionality.
143
149
 
144
150
 
145
151
  Example configuration file:
@@ -166,10 +172,7 @@ environment you are running in.
166
172
 
167
173
  **subscribe|sub**: Add new subscribe. Shortcut to the call of
168
174
  ``.app/broker/currentClient:subscribe`` that accepts arguments in more convenient
169
- way (you need to use Map if you call that method directly). The argument has
170
- same format such as method calls in this tool, that means ``PATH:METHOD`` where
171
- ``METHOD`` can be left out to match all methods. Pattern subscribes are not
172
- supporter, yet.
175
+ way. The argument can be multiple RPC RIs (``PATH:METHOD:SIGNAL`` patterns).
173
176
 
174
177
  **unsubscribe|usub**: Unsubscribe existing subscription. It is reverse operation
175
178
  to the **subscribe** and same remarks apply here as well. It is a shortcut to
@@ -191,11 +194,11 @@ cache.
191
194
  thus use it sparely.
192
195
 
193
196
  **set|s**: allows modification of configuration option in runtime. The names
194
- are the same as in ``config`` section. The boolean options (the only ones
195
- available right now) are set if no argument is provided, or cleared if name is
196
- prefixed with ``no`` (and thus to disable ``raw`` you use ``noraw``). You can
197
- also provide argument ``true`` or ``false``. Without any configuration option it
198
- 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.
199
202
 
200
203
 
201
204
  Special methods ``ls`` and ``dir``
@@ -95,6 +95,12 @@ switched in runtime. The following options are available:
95
95
  * **cache**: Controls if cache is preserved between invocations. Cache is
96
96
  separated based on the connection URL and stored in files in
97
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
103
+ functionality.
98
104
 
99
105
 
100
106
  Example configuration file:
@@ -121,10 +127,7 @@ environment you are running in.
121
127
 
122
128
  **subscribe|sub**: Add new subscribe. Shortcut to the call of
123
129
  ``.app/broker/currentClient:subscribe`` that accepts arguments in more convenient
124
- way (you need to use Map if you call that method directly). The argument has
125
- same format such as method calls in this tool, that means ``PATH:METHOD`` where
126
- ``METHOD`` can be left out to match all methods. Pattern subscribes are not
127
- supporter, yet.
130
+ way. The argument can be multiple RPC RIs (``PATH:METHOD:SIGNAL`` patterns).
128
131
 
129
132
  **unsubscribe|usub**: Unsubscribe existing subscription. It is reverse operation
130
133
  to the **subscribe** and same remarks apply here as well. It is a shortcut to
@@ -146,11 +149,11 @@ cache.
146
149
  thus use it sparely.
147
150
 
148
151
  **set|s**: allows modification of configuration option in runtime. The names
149
- are the same as in ``config`` section. The boolean options (the only ones
150
- available right now) are set if no argument is provided, or cleared if name is
151
- prefixed with ``no`` (and thus to disable ``raw`` you use ``noraw``). You can
152
- also provide argument ``true`` or ``false``. Without any configuration option it
153
- 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.
154
157
 
155
158
 
156
159
  Special methods ``ls`` and ``dir``
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "shvcli"
3
- version = "0.6.0"
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)
@@ -117,9 +119,15 @@ async def handle_line(shvclient: SHVClient, config: CliConfig, cmdline: str) ->
117
119
  else:
118
120
  print_cpon(
119
121
  await shvclient.call(
120
- config.shvpath(items.path), items.method, param
122
+ config.shvpath(items.path),
123
+ items.method,
124
+ param,
125
+ call_attempts=config.call_attempts,
126
+ call_timeout=config.call_timeout,
121
127
  )
122
128
  )
129
+ except TimeoutError:
130
+ print("Call timed out.")
123
131
  except RpcError as exc:
124
132
  print(f"{type(exc).__name__}: {exc.message}")
125
133
  else:
@@ -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"
@@ -4,6 +4,7 @@ import collections.abc
4
4
  import configparser
5
5
  import enum
6
6
  import functools
7
+ import itertools
7
8
  import logging
8
9
  import pathlib
9
10
  import subprocess
@@ -20,6 +21,7 @@ class CliConfig:
20
21
 
21
22
  BOOL = enum.auto()
22
23
  INT = enum.auto()
24
+ FLOAT = enum.auto()
23
25
 
24
26
  OPTS: collections.abc.Mapping[str, Type] = {
25
27
  "vimode": Type.BOOL,
@@ -27,12 +29,21 @@ class CliConfig:
27
29
  "autoprobe": Type.BOOL,
28
30
  "raw": Type.BOOL,
29
31
  "debug": Type.BOOL,
32
+ "call_attempts": Type.INT,
33
+ "call_timeout": Type.FLOAT,
34
+ "autoget_timeout": Type.FLOAT,
30
35
  }
31
- """All options allowed to be set in runtime.
36
+ """Options allowed to be set in runtime and from configuration file.
37
+
32
38
  You can use :func:`setattr` and :func:`getattr`.
33
39
  """
34
40
 
35
- def __init__(self) -> None:
41
+ COPTS: collections.abc.Mapping[str, Type] = {
42
+ "cache": Type.BOOL,
43
+ }
44
+ """Options allowed to be set only from configuration file."""
45
+
46
+ def __init__(self) -> None: # noqa: PLR0915
36
47
  """Initialize the configuration to the default and load config files."""
37
48
  self.hosts: dict[str, RpcUrl] = {}
38
49
  """Hosts that can be used instead of URL."""
@@ -53,6 +64,13 @@ class CliConfig:
53
64
  """Interpret ls and dir method calls internally or not."""
54
65
  self.cache: bool = True
55
66
  """Preserve cache between executions. Not modifiable in runtime!"""
67
+ self.call_attempts: int = 1
68
+ """Number of call attempts before call is abandoned."""
69
+ self.call_timeout: float = 5.0
70
+ """Timeout in seconds before call is abandoned."""
71
+ self.autoget_timeout: float = 1.0
72
+ """Timeout in seconds for call that is part of autoget feature."""
73
+
56
74
  self.initial_scan: bool = False
57
75
  """Perform scan right after connection."""
58
76
  self.initial_scan_depth: int = 3
@@ -74,17 +92,19 @@ class CliConfig:
74
92
  if self.hosts_shell and self.__url is None:
75
93
  self.__url = self.hosts_shell[next(iter(self.hosts_shell))]
76
94
  case "config":
77
- for n, t in self.OPTS.items():
95
+ for n, t in itertools.chain(self.OPTS.items(), self.COPTS.items()):
78
96
  value = getattr(self, n)
79
97
  match t:
80
98
  case self.Type.BOOL:
81
99
  value = sec.getboolean(n, fallback=value)
82
100
  case self.Type.INT:
83
- value = sec.getinteger(n, fallback=value)
101
+ value = sec.getint(n, fallback=value)
102
+ case self.Type.FLOAT:
103
+ value = sec.getfloat(n, fallback=value)
84
104
  case _:
85
105
  raise NotImplementedError(f"Unhandled type: {t!r}")
86
106
  setattr(self, n, value)
87
- if opts := set(sec.keys()) - set(self.OPTS.keys()):
107
+ if opts := set(sec.keys()) - set(self.OPTS) - set(self.COPTS):
88
108
  raise ValueError(
89
109
  f"Invalid configuration option: {', '.join(opts)}"
90
110
  )
@@ -85,9 +85,12 @@ async def ls_method(shvclient: SHVClient, config: CliConfig, items: CliItems) ->
85
85
  if "get" in nv.methods:
86
86
  try:
87
87
  resp = await shvclient.call(
88
- str(pathlib.PurePosixPath(shvpath) / nn), "get"
88
+ str(pathlib.PurePosixPath(shvpath) / nn),
89
+ "get",
90
+ call_attempts=1,
91
+ call_timeout=config.autoget_timeout,
89
92
  )
90
- except RpcError:
93
+ except (RpcError, TimeoutError):
91
94
  pass
92
95
  else:
93
96
  print_row(
@@ -113,8 +116,13 @@ async def dir_method(shvclient: SHVClient, config: CliConfig, items: CliItems) -
113
116
  n = [("", " " * (w - len(d.name))), dir_method_format(d)]
114
117
  if _use_autoget(d):
115
118
  try:
116
- resp = await shvclient.call(shvpath, d.name)
117
- except RpcError:
119
+ resp = await shvclient.call(
120
+ shvpath,
121
+ d.name,
122
+ call_attempts=1,
123
+ call_timeout=config.autoget_timeout,
124
+ )
125
+ except (RpcError, TimeoutError):
118
126
  pass
119
127
  else:
120
128
  print_row(
@@ -59,17 +59,9 @@ class CliItems:
59
59
  path = parts[0] if parts[0] else "**"
60
60
  method = parts[1] if len(parts) == 2 else "*"
61
61
  signal = parts[2] if len(parts) == 3 else "*"
62
- res.append(f"{self.path}{"/" if self.path else ""}{path}:{method}:{signal}")
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)
@@ -141,7 +141,7 @@ def print_cpon(data: shv.SHVType, prefix: str = "", short: bool = False) -> None
141
141
  cpon = "\n".join(_wrap_cpon(prefix + shv.Cpon.pack(data)))[len(prefix) :]
142
142
  print_ftext(itertools.chain(iter((("", prefix),)), cpon_ftext(cpon)))
143
143
  else:
144
- print_row(
144
+ print_ftext(
145
145
  itertools.chain(
146
146
  iter((("", prefix),)),
147
147
  cpon_ftext(shv.Cpon.pack(data, shv.CponWriter.Options(indent=b" "))),
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: shvcli
3
- Version: 0.6.0
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
@@ -140,6 +140,12 @@ switched in runtime. The following options are available:
140
140
  * **cache**: Controls if cache is preserved between invocations. Cache is
141
141
  separated based on the connection URL and stored in files in
142
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
148
+ functionality.
143
149
 
144
150
 
145
151
  Example configuration file:
@@ -166,10 +172,7 @@ environment you are running in.
166
172
 
167
173
  **subscribe|sub**: Add new subscribe. Shortcut to the call of
168
174
  ``.app/broker/currentClient:subscribe`` that accepts arguments in more convenient
169
- way (you need to use Map if you call that method directly). The argument has
170
- same format such as method calls in this tool, that means ``PATH:METHOD`` where
171
- ``METHOD`` can be left out to match all methods. Pattern subscribes are not
172
- supporter, yet.
175
+ way. The argument can be multiple RPC RIs (``PATH:METHOD:SIGNAL`` patterns).
173
176
 
174
177
  **unsubscribe|usub**: Unsubscribe existing subscription. It is reverse operation
175
178
  to the **subscribe** and same remarks apply here as well. It is a shortcut to
@@ -191,11 +194,11 @@ cache.
191
194
  thus use it sparely.
192
195
 
193
196
  **set|s**: allows modification of configuration option in runtime. The names
194
- are the same as in ``config`` section. The boolean options (the only ones
195
- available right now) are set if no argument is provided, or cleared if name is
196
- prefixed with ``no`` (and thus to disable ``raw`` you use ``noraw``). You can
197
- also provide argument ``true`` or ``false``. Without any configuration option it
198
- 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.
199
202
 
200
203
 
201
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