shvcli 0.3.0__tar.gz → 0.4.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 (31) hide show
  1. {shvcli-0.3.0/shvcli.egg-info → shvcli-0.4.0}/PKG-INFO +7 -12
  2. {shvcli-0.3.0 → shvcli-0.4.0}/README.rst +3 -3
  3. shvcli-0.4.0/pyproject.toml +101 -0
  4. shvcli-0.4.0/shvcli/__init__.py +5 -0
  5. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/__main__.py +1 -0
  6. shvcli-0.4.0/shvcli/__version__.py +25 -0
  7. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/builtin.py +1 -0
  8. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/builtin_impl.py +5 -6
  9. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/cli.py +4 -3
  10. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/client.py +29 -18
  11. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/complet.py +3 -2
  12. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/complet_tools.py +1 -0
  13. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/config.py +3 -2
  14. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/lsdir.py +11 -7
  15. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/parse.py +5 -5
  16. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/scan.py +1 -0
  17. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/tools.py +4 -3
  18. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/valid.py +3 -2
  19. {shvcli-0.3.0 → shvcli-0.4.0/shvcli.egg-info}/PKG-INFO +7 -12
  20. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli.egg-info/SOURCES.txt +1 -0
  21. shvcli-0.4.0/shvcli.egg-info/requires.txt +4 -0
  22. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli.egg-info/top_level.txt +1 -0
  23. shvcli-0.3.0/pyproject.toml +0 -89
  24. shvcli-0.3.0/shvcli/__init__.py +0 -5
  25. shvcli-0.3.0/shvcli.egg-info/requires.txt +0 -10
  26. {shvcli-0.3.0 → shvcli-0.4.0}/LICENSE +0 -0
  27. {shvcli-0.3.0 → shvcli-0.4.0}/setup.cfg +0 -0
  28. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/py.typed +0 -0
  29. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli/version +0 -0
  30. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli.egg-info/dependency_links.txt +0 -0
  31. {shvcli-0.3.0 → shvcli-0.4.0}/shvcli.egg-info/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shvcli
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Silicon Heaven CLI access application
5
5
  Author: Elektroline a.s.
6
6
  License: MIT License
@@ -25,7 +25,7 @@ License: MIT License
25
25
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
26
  SOFTWARE.
27
27
 
28
- Project-URL: repository, https://gitlab.com/elektroline-predator/shvcli
28
+ Project-URL: repository, https://gitlab.com/silicon-heaven/shvcli
29
29
  Classifier: Development Status :: 4 - Beta
30
30
  Classifier: License :: OSI Approved :: MIT License
31
31
  Classifier: Programming Language :: Python :: 3
@@ -38,27 +38,22 @@ 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.5.0
41
+ Requires-Dist: pyshv>=0.6.0
42
42
  Requires-Dist: prompt_toolkit
43
+ Requires-Dist: pygments
43
44
  Requires-Dist: pyxdg
44
- Provides-Extra: lint
45
- Requires-Dist: black; extra == "lint"
46
- Requires-Dist: isort; extra == "lint"
47
- Requires-Dist: mypy; extra == "lint"
48
- Requires-Dist: pydocstyle; extra == "lint"
49
- Requires-Dist: pylint; extra == "lint"
50
45
 
51
46
  =====================================
52
47
  Silicon Heaven CLI access application
53
48
  =====================================
54
- .. image:: https://gitlab.com/elektroline-predator/shvcli/-/raw/master/logo.svg
49
+ .. image:: https://gitlab.com/silicon-heaven/shvcli/-/raw/master/logo.svg
55
50
  :align: right
56
51
  :height: 128px
57
52
 
58
53
  This provides an easy to use CLI interfase to access the SHV network.
59
54
 
60
- * `📃 Sources <https://gitlab.com/elektroline-predator/shvcli>`__
61
- * `⁉️ Issue tracker <https://gitlab.com/elektroline-predator/shvcli/-/issues>`__
55
+ * `📃 Sources <https://gitlab.com/silicon-heaven/shvcli>`__
56
+ * `⁉️ Issue tracker <https://gitlab.com/silicon-heaven/shvcli/-/issues>`__
62
57
  * `📕 Silicon Heaven protocol documentation <https://silicon-heaven.github.io/shv-doc/>`__
63
58
 
64
59
 
@@ -1,14 +1,14 @@
1
1
  =====================================
2
2
  Silicon Heaven CLI access application
3
3
  =====================================
4
- .. image:: https://gitlab.com/elektroline-predator/shvcli/-/raw/master/logo.svg
4
+ .. image:: https://gitlab.com/silicon-heaven/shvcli/-/raw/master/logo.svg
5
5
  :align: right
6
6
  :height: 128px
7
7
 
8
8
  This provides an easy to use CLI interfase to access the SHV network.
9
9
 
10
- * `📃 Sources <https://gitlab.com/elektroline-predator/shvcli>`__
11
- * `⁉️ Issue tracker <https://gitlab.com/elektroline-predator/shvcli/-/issues>`__
10
+ * `📃 Sources <https://gitlab.com/silicon-heaven/shvcli>`__
11
+ * `⁉️ Issue tracker <https://gitlab.com/silicon-heaven/shvcli/-/issues>`__
12
12
  * `📕 Silicon Heaven protocol documentation <https://silicon-heaven.github.io/shv-doc/>`__
13
13
 
14
14
 
@@ -0,0 +1,101 @@
1
+ [project]
2
+ name = "shvcli"
3
+ version = "0.4.0"
4
+ description = "Silicon Heaven CLI access application"
5
+ readme = "README.rst"
6
+ license = {file = "LICENSE"}
7
+ authors = [
8
+ { name="Elektroline a.s." },
9
+ ]
10
+ classifiers = [
11
+ "Development Status :: 4 - Beta",
12
+ "License :: OSI Approved :: MIT License",
13
+ "Programming Language :: Python :: 3",
14
+ "Operating System :: OS Independent",
15
+ "Environment :: Console",
16
+ "Intended Audience :: End Users/Desktop",
17
+ "Topic :: Home Automation",
18
+ "Topic :: System :: Shells",
19
+ "Topic :: Terminals",
20
+ ]
21
+ requires-python = ">=3.11"
22
+ dependencies = [
23
+ "pyshv >= 0.6.0",
24
+ "prompt_toolkit",
25
+ "pygments",
26
+ "pyxdg",
27
+ ]
28
+
29
+ [project.urls]
30
+ repository = "https://gitlab.com/silicon-heaven/shvcli"
31
+
32
+ [project.scripts]
33
+ shvcli = "shvcli.__main__:main"
34
+
35
+ [build-system]
36
+ requires = ["setuptools"]
37
+ build-backend = "setuptools.build_meta"
38
+
39
+ [tool.setuptools.packages.find]
40
+ [tool.setuptools.package-data]
41
+ "*" = ["py.typed"]
42
+
43
+ [tool.coverage.run]
44
+ branch = true
45
+ [tool.coverage.report]
46
+ exclude_lines = [
47
+ "pragma: no cover",
48
+ "if typing.TYPE_CHECKING:"
49
+ ]
50
+
51
+ [tool.ruff]
52
+ target-version = "py311"
53
+ [tool.ruff.lint]
54
+ select = [
55
+ "F", "E", "W", "I", "N", "D", "UP", "YTT", "ANN", "ASYNC", "TRIO", "S", "BLE",
56
+ "B", "A", "COM", "PL", "RUF"
57
+ ]
58
+ ignore = [
59
+ # Magic methods have defined behavior so what is there to document. __init__
60
+ # should be documented in class docstring.
61
+ "D105", "D107",
62
+ # These have conflicting rules.
63
+ "D203", "D213",
64
+ # Ignore too long lines (format tackles that)
65
+ "E501",
66
+ # It is nice that assert should not be used for input checking but it can be
67
+ # also used for internal consistency checking.
68
+ "S101", "B011",
69
+ # subprocess can be insecurely used but not is insecure by design
70
+ "S404", "S603", "S607",
71
+ # Catching Exception is valid and safe in some cases and thus should be allowed
72
+ "BLE001",
73
+ # Conflict with formatter
74
+ "COM812",
75
+ # Remove too-many limit for more complex code.
76
+ "PLR0904", "PLR0911", "PLR0912", "PLR0913", "PLR0917", "PLR2004", "PLR1702",
77
+ "PLR0916",
78
+ # This seems like a wrong rule
79
+ "PLW1641",
80
+ # Deprecated
81
+ "ANN101", "ANN102",
82
+ ]
83
+ preview = true
84
+ [tool.ruff.lint.per-file-ignores]
85
+ "tests/**" = [
86
+ "D100", "D101", "D102", "D103", "D104", "S101", "S106", "ANN001", "ANN002",
87
+ "ANN003", "ANN201", "ANN202", "ANN204", "ANN205", "PLR6301",
88
+ ]
89
+ "docs/conf.py" = ["D100", "D103", "A001", "ANN201", "ANN001"]
90
+ [tool.ruff.format]
91
+ docstring-code-format = true
92
+ preview = true
93
+
94
+ [tool.mypy]
95
+ python_version = "3.11"
96
+ ignore_missing_imports = true
97
+ disallow_untyped_defs = true
98
+ warn_redundant_casts = true
99
+ warn_unused_ignores = true
100
+ warn_return_any = true
101
+ warn_unreachable = true
@@ -0,0 +1,5 @@
1
+ """Silicon Heaven Command Line Interface."""
2
+
3
+ from .__version__ import VERSION
4
+
5
+ __all__ = ["VERSION"]
@@ -1,4 +1,5 @@
1
1
  """Implementation of command line application."""
2
+
2
3
  import argparse
3
4
  import asyncio
4
5
  import logging
@@ -0,0 +1,25 @@
1
+ """The smarter loader of the version.
2
+
3
+ It identifies if this package is installed and returns version from egg info or
4
+ it looks for pyproject.toml file in upper directory.
5
+ """
6
+
7
+ import importlib.metadata
8
+ import pathlib
9
+ import tomllib
10
+
11
+
12
+ def _get_version() -> str:
13
+ for dist_name in importlib.metadata.packages_distributions().get(__package__, []):
14
+ dist = importlib.metadata.distribution(dist_name)
15
+ if str(dist.locate_file(f"{__package__}/__version__.py")) == __file__:
16
+ return dist.version
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
22
+ return "unknown"
23
+
24
+
25
+ VERSION = _get_version()
@@ -1,4 +1,5 @@
1
1
  """Builtin methods glue code so they can be defined separatelly."""
2
+
2
3
  import collections.abc
3
4
  import dataclasses
4
5
  import typing
@@ -1,4 +1,5 @@
1
1
  """Implementations of our builtin methods."""
2
+
2
3
  import collections.abc
3
4
  import inspect
4
5
  import itertools
@@ -95,12 +96,10 @@ async def tree(shvclient: SHVClient, config: CliConfig, items: CliItems) -> None
95
96
  print_ftext(
96
97
  itertools.chain(
97
98
  (("", "│ " if c else " ") for c in cols),
98
- iter(
99
- [
100
- ("", "├─" if hasnext else "└─"),
101
- ls_node_format(name, parent_node=node),
102
- ]
103
- ),
99
+ iter([
100
+ ("", "├─" if hasnext else "└─"),
101
+ ls_node_format(name, parent_node=node),
102
+ ]),
104
103
  )
105
104
  )
106
105
  print_node(node[name], [*cols, hasnext])
@@ -1,4 +1,5 @@
1
1
  """Command line interface."""
2
+
2
3
  import asyncio
3
4
  import json
4
5
  import pathlib
@@ -8,9 +9,9 @@ import xdg.BaseDirectory
8
9
  from prompt_toolkit import PromptSession
9
10
  from prompt_toolkit.history import FileHistory
10
11
  from prompt_toolkit.patch_stdout import patch_stdout
11
- from shv import RpcError, RpcUrl
12
+ from shv import RpcError, RpcLogin, RpcUrl
12
13
 
13
- from . import builtin_impl as _
14
+ from . import builtin_impl as _ # noqa F401
14
15
  from .builtin import call_builtin
15
16
  from .client import Node, SHVClient
16
17
  from .complet import CliCompleter
@@ -68,7 +69,7 @@ async def run(config: CliConfig) -> None:
68
69
  location=config.url.location,
69
70
  port=config.url.port,
70
71
  protocol=config.url.protocol,
71
- username=config.url.username,
72
+ login=RpcLogin(username=config.url.login.username),
72
73
  )
73
74
  cpath = xdg.BaseDirectory.save_cache_path("shvcli")
74
75
  fname = re.sub(r"[^\w_. -]", "_", cacheurl.to_url())
@@ -1,4 +1,5 @@
1
1
  """SHV client for shvcli."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import collections.abc
@@ -6,7 +7,6 @@ import typing
6
7
  from pathlib import PurePosixPath
7
8
 
8
9
  from shv import (
9
- RpcClient,
10
10
  RpcError,
11
11
  RpcMessage,
12
12
  RpcMethodDesc,
@@ -31,7 +31,7 @@ class Node(collections.abc.Mapping[str, "Node"]):
31
31
  self.nodes_probed = False
32
32
  self.methods_probed = False
33
33
 
34
- def __getitem__(self, key: str) -> "Node":
34
+ def __getitem__(self, key: str) -> Node:
35
35
  """Get node from nodes."""
36
36
  return self.nodes[key]
37
37
 
@@ -43,7 +43,7 @@ class Node(collections.abc.Mapping[str, "Node"]):
43
43
  """Get number of child nodes."""
44
44
  return len(self.nodes)
45
45
 
46
- def valid_path(self, path: str | PurePosixPath) -> "Node":
46
+ def valid_path(self, path: str | PurePosixPath) -> Node:
47
47
  """Add valid path relative to this node."""
48
48
  if isinstance(path, str):
49
49
  path = PurePosixPath(path)
@@ -68,7 +68,7 @@ class Node(collections.abc.Mapping[str, "Node"]):
68
68
  if pnode is not None:
69
69
  pnode.nodes.pop(path.name)
70
70
 
71
- def get_path(self, path: str | PurePosixPath) -> typing.Union[None, "Node"]:
71
+ def get_path(self, path: str | PurePosixPath) -> None | Node:
72
72
  """Get node on given path."""
73
73
  if isinstance(path, str):
74
74
  path = PurePosixPath(path)
@@ -79,7 +79,7 @@ class Node(collections.abc.Mapping[str, "Node"]):
79
79
  node = node[n]
80
80
  return node
81
81
 
82
- def dump(self) -> typing.Any:
82
+ def dump(self) -> dict[str, object]:
83
83
  """Dump the data to basic types."""
84
84
  return {
85
85
  "nodes": {n: v.dump() for n, v in self.nodes.items()},
@@ -90,15 +90,18 @@ class Node(collections.abc.Mapping[str, "Node"]):
90
90
  }
91
91
 
92
92
  @classmethod
93
- def load(cls, data: typing.Any) -> Node:
93
+ def load(cls, data: collections.abc.Mapping[str, object]) -> Node:
94
94
  """Load node tree from dump."""
95
95
  assert isinstance(data, collections.abc.Mapping)
96
96
  res = cls()
97
- res.nodes = {n: cls.load(v) for n, v in data["nodes"].items()}
98
- res.methods = set(data["methods"])
99
- res.signals = set(data["signals"])
100
- res.nodes_probed = data["nodes_probed"]
101
- res.methods_probed = data["methods_probed"]
97
+ if isinstance(data["nodes"], collections.abc.Mapping):
98
+ 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"])
103
+ res.nodes_probed = bool(data["nodes_probed"])
104
+ res.methods_probed = bool(data["methods_probed"])
102
105
  return res
103
106
 
104
107
 
@@ -108,11 +111,11 @@ class SHVClient(SimpleClient):
108
111
  APP_NAME = "shvcli"
109
112
  APP_VERSION = VERSION
110
113
 
111
- def __init__(self, client: RpcClient) -> None:
114
+ def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: # noqa ANN401
112
115
  """Initialize client and set create reference to tree."""
113
116
  self.tree = Node()
114
117
  self.tree.valid_path(".app")
115
- super().__init__(client)
118
+ super().__init__(*args, **kwargs)
116
119
 
117
120
  async def _loop(self) -> None:
118
121
  await super()._loop()
@@ -150,19 +153,27 @@ class SHVClient(SimpleClient):
150
153
  self.tree.invalid_path(path)
151
154
  raise exc
152
155
  node = self.tree.valid_path(path)
153
- node.methods = {d.name for d in res if RpcMethodFlags.SIGNAL not in d.flags}
154
- node.signals = {d.name for d in res if RpcMethodFlags.SIGNAL in d.flags}
156
+ node.methods = {
157
+ d.name for d in res if RpcMethodFlags.NOT_CALLABLE not in d.flags
158
+ }
159
+ node.signals = {d.name for d in res if RpcMethodFlags.NOT_CALLABLE in d.flags}
155
160
  node.methods_probed = True
156
161
  return res
157
162
 
158
- async def call(self, path: str, method: str, param: SHVType = None) -> SHVType:
163
+ async def call(
164
+ self,
165
+ path: str,
166
+ method: str,
167
+ *args: typing.Any, # noqa ANN401
168
+ **kwargs: typing.Any, # noqa ANN401
169
+ ) -> SHVType:
159
170
  """Perform call same as ValueClient.
160
171
 
161
172
  This uses every call to get insite into existence of method and node and records
162
173
  that in the tree.
163
174
  """
164
175
  try:
165
- res = await super().call(path, method, param)
176
+ res = await super().call(path, method, *args, **kwargs)
166
177
  except RpcMethodNotFoundError as exc:
167
178
  raise exc
168
179
  except RpcError as exc:
@@ -190,7 +201,7 @@ class SHVClient(SimpleClient):
190
201
  async def path_is_valid(self, path: str) -> bool:
191
202
  """Check if given path is valid by using ls command."""
192
203
  path = path.strip("/")
193
- if path == "":
204
+ if not path:
194
205
  return True # top level is always valid
195
206
  if "/" in path:
196
207
  pth, name = path.rsplit("/", maxsplit=1)
@@ -1,4 +1,5 @@
1
1
  """Completion for CLI."""
2
+
2
3
  import collections.abc
3
4
  import typing
4
5
 
@@ -28,7 +29,7 @@ class CliCompleter(Completer):
28
29
 
29
30
  # Parameters
30
31
  if CliFlags.COMPLETE_CALL in items.flags:
31
- if items.method in ("ls", "dir") and not self.config.raw:
32
+ if items.method in {"ls", "dir"} and not self.config.raw:
32
33
  yield from comp_path(self.shvclient, self.config, items)
33
34
  elif bmethod := builtin.get_builtin(items.method[1:]):
34
35
  if bmethod.argument:
@@ -58,7 +59,7 @@ class CliCompleter(Completer):
58
59
  items = parse_line(document.text)
59
60
  if self.config.autoprobe and (
60
61
  CliFlags.COMPLETE_CALL not in items.flags
61
- or items.method in ("ls", "dir")
62
+ or items.method in {"ls", "dir"}
62
63
  or (
63
64
  items.method[0] == "!"
64
65
  and (bmethod := builtin.get_builtin(items.method[1:])) is not None
@@ -1,4 +1,5 @@
1
1
  """Tool for completion algorithms."""
2
+
2
3
  import collections.abc
3
4
  import pathlib
4
5
 
@@ -1,4 +1,5 @@
1
1
  """Configuration state of the CLI."""
2
+
2
3
  import collections.abc
3
4
  import configparser
4
5
  import enum
@@ -102,7 +103,7 @@ class CliConfig:
102
103
  self.__rurl = RpcUrl.parse(
103
104
  subprocess.run(
104
105
  f"printf '%s' \"{self.__url}\"",
105
- shell=True,
106
+ shell=True, # noqa S602
106
107
  stdout=subprocess.PIPE,
107
108
  check=True,
108
109
  ).stdout.decode()
@@ -128,7 +129,7 @@ class CliConfig:
128
129
  return logging.root.level <= logging.DEBUG
129
130
 
130
131
  @debug.setter
131
- def debug(self, value: bool) -> None:
132
+ def debug(self, value: bool) -> None: # noqa PLR6301
132
133
  logging.root.setLevel(logging.DEBUG if value else logging.WARNING)
133
134
 
134
135
  def shvpath(
@@ -1,4 +1,5 @@
1
1
  """Special handling of ls and dir methods."""
2
+
2
3
  import itertools
3
4
  import pathlib
4
5
  import string
@@ -32,14 +33,17 @@ def ls_node_format(
32
33
  def dir_method_format(method: RpcMethodDesc) -> tuple[str, str]:
33
34
  """Print format for single method info."""
34
35
  methstyle = ""
35
- if RpcMethodFlags.SIGNAL in method.flags:
36
- methstyle = "ansipurple"
36
+ if method.name in {"ls", "dir"}:
37
+ methstyle = "ansibrightblack"
37
38
  elif RpcMethodFlags.SETTER in method.flags:
38
39
  methstyle = "ansiyellow"
39
40
  elif RpcMethodFlags.GETTER in method.flags:
40
- methstyle = "ansigreen"
41
- elif method.name in ("ls", "dir"):
42
- methstyle = "ansibrightblack"
41
+ if method.signals:
42
+ methstyle = "ansimagenta"
43
+ else:
44
+ methstyle = "ansigreen"
45
+ elif method.signals or RpcMethodFlags.NOT_CALLABLE in method.flags:
46
+ methstyle = "ansipurple"
43
47
  name = method.name
44
48
  return (
45
49
  methstyle,
@@ -74,7 +78,7 @@ async def ls_method(shvclient: SHVClient, config: CliConfig, items: CliItems) ->
74
78
  else:
75
79
  print_row(
76
80
  itertools.chain(
77
- iter(n + [("", " ")]), cpon_ftext(Cpon.pack(resp))
81
+ iter([*n, ("", " ")]), cpon_ftext(Cpon.pack(resp))
78
82
  )
79
83
  )
80
84
  continue
@@ -99,7 +103,7 @@ async def dir_method(shvclient: SHVClient, config: CliConfig, items: CliItems) -
99
103
  else:
100
104
  print_row(
101
105
  itertools.chain(
102
- iter(n + [("", " ")]), cpon_ftext(Cpon.pack(resp))
106
+ iter([*n, ("", " ")]), cpon_ftext(Cpon.pack(resp))
103
107
  )
104
108
  )
105
109
  continue
@@ -1,4 +1,5 @@
1
1
  """Implementation of CLI parser."""
2
+
2
3
  import dataclasses
3
4
  import enum
4
5
 
@@ -28,7 +29,7 @@ class CliItems:
28
29
  param_raw: str = ""
29
30
  """Raw parameter passed from CLI."""
30
31
 
31
- flags: CliFlags = CliFlags(0)
32
+ flags: CliFlags = dataclasses.field(default_factory=lambda: CliFlags(0))
32
33
  """Flags signaling the presence of some important dividers."""
33
34
 
34
35
  @property
@@ -84,9 +85,8 @@ def parse_line(line: str) -> CliItems:
84
85
  if ":" in line:
85
86
  res.flags |= CliFlags.HAS_COLON
86
87
  res.path, res.method = line.split(":", maxsplit=1)
88
+ elif "/" in line:
89
+ res.path = line
87
90
  else:
88
- if "/" in line:
89
- res.path = line
90
- else:
91
- res.method = line
91
+ res.method = line
92
92
  return res
@@ -3,6 +3,7 @@
3
3
  Implementated sepratelly so we can use it not only from builtin methods but also
4
4
  directly when configured.
5
5
  """
6
+
6
7
  from prompt_toolkit.shortcuts import ProgressBar, ProgressBarCounter
7
8
 
8
9
  from .client import SHVClient
@@ -1,4 +1,5 @@
1
1
  """Various tools used in the code."""
2
+
2
3
  import collections.abc
3
4
  import os
4
5
  import textwrap
@@ -39,7 +40,7 @@ def intersperse(what: T, iterin: typing.Iterable[T]) -> typing.Iterator[T]:
39
40
 
40
41
  def print_ftext(
41
42
  fstrs: collections.abc.Iterable[tuple[str, str]]
42
- | collections.abc.Iterator[tuple[str, str]]
43
+ | collections.abc.Iterator[tuple[str, str]],
43
44
  ) -> None:
44
45
  """Call :meth:`print_formatted_text` with :class:`FormattedText`."""
45
46
  print_formatted_text(FormattedText(fstrs))
@@ -47,7 +48,7 @@ def print_ftext(
47
48
 
48
49
  def print_flist(
49
50
  fstrs: collections.abc.Iterable[tuple[str, str]]
50
- | collections.abc.Iterator[tuple[str, str]]
51
+ | collections.abc.Iterator[tuple[str, str]],
51
52
  ) -> None:
52
53
  """Print with :meth:`print_ftext` but interperse spaces."""
53
54
  cols = os.get_terminal_size().columns
@@ -70,7 +71,7 @@ def print_row(
70
71
  ftext: collections.abc.Iterable[tuple[str, str]]
71
72
  | collections.abc.Iterator[tuple[str, str]]
72
73
  | tuple[str, str]
73
- | str
74
+ | str,
74
75
  ) -> None:
75
76
  """Print one line with hyphens when needed."""
76
77
  if isinstance(ftext, str):
@@ -1,4 +1,5 @@
1
1
  """Validator for CLI."""
2
+
2
3
  from prompt_toolkit.document import Document
3
4
  from prompt_toolkit.validation import ValidationError, Validator
4
5
 
@@ -22,7 +23,7 @@ class CliValidator(Validator):
22
23
 
23
24
  # Parameters
24
25
  if CliFlags.COMPLETE_CALL in items.flags:
25
- if items.method in ("ls", "dir") and not self.config.raw:
26
+ if items.method in {"ls", "dir"} and not self.config.raw:
26
27
  return
27
28
  if builtin.get_builtin(items.method[1:]):
28
29
  # TODO we can add validation to the builtins as well
@@ -30,7 +31,7 @@ class CliValidator(Validator):
30
31
  # Any other command should have CPON as argument and thus validate
31
32
  # it as such.
32
33
  try:
33
- items.param
34
+ _ = items.param
34
35
  except (ValueError, EOFError) as exc:
35
36
  raise ValidationError(message=f"Invalid CPON: {exc}") from exc
36
37
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shvcli
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Silicon Heaven CLI access application
5
5
  Author: Elektroline a.s.
6
6
  License: MIT License
@@ -25,7 +25,7 @@ License: MIT License
25
25
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
26
  SOFTWARE.
27
27
 
28
- Project-URL: repository, https://gitlab.com/elektroline-predator/shvcli
28
+ Project-URL: repository, https://gitlab.com/silicon-heaven/shvcli
29
29
  Classifier: Development Status :: 4 - Beta
30
30
  Classifier: License :: OSI Approved :: MIT License
31
31
  Classifier: Programming Language :: Python :: 3
@@ -38,27 +38,22 @@ 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.5.0
41
+ Requires-Dist: pyshv>=0.6.0
42
42
  Requires-Dist: prompt_toolkit
43
+ Requires-Dist: pygments
43
44
  Requires-Dist: pyxdg
44
- Provides-Extra: lint
45
- Requires-Dist: black; extra == "lint"
46
- Requires-Dist: isort; extra == "lint"
47
- Requires-Dist: mypy; extra == "lint"
48
- Requires-Dist: pydocstyle; extra == "lint"
49
- Requires-Dist: pylint; extra == "lint"
50
45
 
51
46
  =====================================
52
47
  Silicon Heaven CLI access application
53
48
  =====================================
54
- .. image:: https://gitlab.com/elektroline-predator/shvcli/-/raw/master/logo.svg
49
+ .. image:: https://gitlab.com/silicon-heaven/shvcli/-/raw/master/logo.svg
55
50
  :align: right
56
51
  :height: 128px
57
52
 
58
53
  This provides an easy to use CLI interfase to access the SHV network.
59
54
 
60
- * `📃 Sources <https://gitlab.com/elektroline-predator/shvcli>`__
61
- * `⁉️ Issue tracker <https://gitlab.com/elektroline-predator/shvcli/-/issues>`__
55
+ * `📃 Sources <https://gitlab.com/silicon-heaven/shvcli>`__
56
+ * `⁉️ Issue tracker <https://gitlab.com/silicon-heaven/shvcli/-/issues>`__
62
57
  * `📕 Silicon Heaven protocol documentation <https://silicon-heaven.github.io/shv-doc/>`__
63
58
 
64
59
 
@@ -3,6 +3,7 @@ README.rst
3
3
  pyproject.toml
4
4
  shvcli/__init__.py
5
5
  shvcli/__main__.py
6
+ shvcli/__version__.py
6
7
  shvcli/builtin.py
7
8
  shvcli/builtin_impl.py
8
9
  shvcli/cli.py
@@ -0,0 +1,4 @@
1
+ pyshv>=0.6.0
2
+ prompt_toolkit
3
+ pygments
4
+ pyxdg
@@ -1 +1,2 @@
1
+ dist
1
2
  shvcli
@@ -1,89 +0,0 @@
1
- [project]
2
- name = "shvcli"
3
- description = "Silicon Heaven CLI access application"
4
- readme = "README.rst"
5
- license = {file = "LICENSE"}
6
- dynamic = ["version"]
7
- authors = [
8
- { name="Elektroline a.s." },
9
- ]
10
- classifiers = [
11
- "Development Status :: 4 - Beta",
12
- "License :: OSI Approved :: MIT License",
13
- "Programming Language :: Python :: 3",
14
- "Operating System :: OS Independent",
15
- "Environment :: Console",
16
- "Intended Audience :: End Users/Desktop",
17
- "Topic :: Home Automation",
18
- "Topic :: System :: Shells",
19
- "Topic :: Terminals",
20
- ]
21
- requires-python = ">=3.11"
22
- dependencies = [
23
- "pyshv >= 0.5.0",
24
- "prompt_toolkit",
25
- "pyxdg",
26
- ]
27
-
28
- [project.urls]
29
- repository = "https://gitlab.com/elektroline-predator/shvcli"
30
-
31
- [project.optional-dependencies]
32
- lint = [
33
- "black",
34
- "isort",
35
- "mypy",
36
- "pydocstyle",
37
- "pylint",
38
- ]
39
-
40
- [project.scripts]
41
- shvcli = "shvcli.__main__:main"
42
-
43
- [build-system]
44
- requires = ["setuptools"]
45
- build-backend = "setuptools.build_meta"
46
-
47
- [tool.setuptools.dynamic]
48
- version = {file = "shvcli/version"}
49
- [tool.setuptools.package-data]
50
- "*" = ["version", "py.typed"]
51
-
52
- [tool.coverage.run]
53
- branch = true
54
- [tool.coverage.report]
55
- exclude_lines = [
56
- "pragma: no cover",
57
- "if typing.TYPE_CHECKING:"
58
- ]
59
-
60
- [tool.isort]
61
- profile = 'black'
62
-
63
- [tool.pylint.main]
64
- recursive = "y"
65
- fail-under = 9.5
66
- [tool.pylint.format]
67
- disable = [
68
- # Exception can be safely caught because there is BaseException for unsafe
69
- # ones (such as SystemExit) and there are reasons to catch all exceptions.
70
- "W0718",
71
- # Prevent usage of module name in documentation (seems unreasonable)
72
- "C0104",
73
- # We have pydocstyle for the following ones
74
- "C0103", "C0114", "C0115", "C0116",
75
- ]
76
- # https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html
77
- max-line-length = 88
78
-
79
- [tool.mypy]
80
- python_version = "3.11"
81
- ignore_missing_imports = true
82
- disallow_untyped_defs = true
83
- warn_redundant_casts = true
84
- warn_unused_ignores = true
85
- warn_return_any = true
86
- warn_unreachable = true
87
-
88
- [tool.pydocstyle]
89
- convention = "pep257"
@@ -1,5 +0,0 @@
1
- """Silicon Heaven Command Line Interface."""
2
-
3
- VERSION = (
4
- (__import__("pathlib").Path(__file__).parent / "version").read_text("utf-8").strip()
5
- )
@@ -1,10 +0,0 @@
1
- pyshv>=0.5.0
2
- prompt_toolkit
3
- pyxdg
4
-
5
- [lint]
6
- black
7
- isort
8
- mypy
9
- pydocstyle
10
- pylint
File without changes
File without changes
File without changes
File without changes