moat-kv 0.71.0__py3-none-any.whl → 0.71.7__py3-none-any.whl

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 (178) hide show
  1. moat/kv/__init__.py +6 -7
  2. moat/kv/_cfg.yaml +3 -2
  3. moat/kv/actor/__init__.py +2 -1
  4. moat/kv/actor/deletor.py +4 -1
  5. moat/kv/auth/__init__.py +12 -13
  6. moat/kv/auth/_test.py +4 -1
  7. moat/kv/auth/password.py +11 -7
  8. moat/kv/backend/mqtt.py +4 -5
  9. moat/kv/client.py +20 -39
  10. moat/kv/code.py +3 -3
  11. moat/kv/command/data.py +4 -3
  12. moat/kv/command/dump/__init__.py +36 -34
  13. moat/kv/command/internal.py +2 -3
  14. moat/kv/command/job.py +1 -2
  15. moat/kv/command/type.py +3 -6
  16. moat/kv/data.py +9 -8
  17. moat/kv/errors.py +16 -8
  18. moat/kv/mock/__init__.py +2 -12
  19. moat/kv/model.py +29 -33
  20. moat/kv/obj/__init__.py +3 -3
  21. moat/kv/obj/command.py +3 -3
  22. moat/kv/runner.py +4 -5
  23. moat/kv/server.py +106 -126
  24. moat/kv/types.py +10 -12
  25. {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/METADATA +6 -2
  26. moat_kv-0.71.7.dist-info/RECORD +47 -0
  27. {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/WHEEL +1 -1
  28. moat_kv-0.71.7.dist-info/licenses/LICENSE +3 -0
  29. moat_kv-0.71.7.dist-info/licenses/LICENSE.APACHE2 +202 -0
  30. moat_kv-0.71.7.dist-info/licenses/LICENSE.MIT +20 -0
  31. moat_kv-0.71.7.dist-info/top_level.txt +1 -0
  32. build/lib/docs/source/conf.py +0 -201
  33. build/lib/examples/pathify.py +0 -45
  34. build/lib/moat/kv/__init__.py +0 -19
  35. build/lib/moat/kv/_cfg.yaml +0 -93
  36. build/lib/moat/kv/_main.py +0 -91
  37. build/lib/moat/kv/actor/__init__.py +0 -98
  38. build/lib/moat/kv/actor/deletor.py +0 -139
  39. build/lib/moat/kv/auth/__init__.py +0 -444
  40. build/lib/moat/kv/auth/_test.py +0 -166
  41. build/lib/moat/kv/auth/password.py +0 -234
  42. build/lib/moat/kv/auth/root.py +0 -58
  43. build/lib/moat/kv/backend/__init__.py +0 -67
  44. build/lib/moat/kv/backend/mqtt.py +0 -71
  45. build/lib/moat/kv/client.py +0 -1025
  46. build/lib/moat/kv/code.py +0 -236
  47. build/lib/moat/kv/codec.py +0 -11
  48. build/lib/moat/kv/command/__init__.py +0 -1
  49. build/lib/moat/kv/command/acl.py +0 -180
  50. build/lib/moat/kv/command/auth.py +0 -261
  51. build/lib/moat/kv/command/code.py +0 -293
  52. build/lib/moat/kv/command/codec.py +0 -186
  53. build/lib/moat/kv/command/data.py +0 -265
  54. build/lib/moat/kv/command/dump/__init__.py +0 -143
  55. build/lib/moat/kv/command/error.py +0 -149
  56. build/lib/moat/kv/command/internal.py +0 -248
  57. build/lib/moat/kv/command/job.py +0 -433
  58. build/lib/moat/kv/command/log.py +0 -53
  59. build/lib/moat/kv/command/server.py +0 -114
  60. build/lib/moat/kv/command/type.py +0 -201
  61. build/lib/moat/kv/config.py +0 -46
  62. build/lib/moat/kv/data.py +0 -216
  63. build/lib/moat/kv/errors.py +0 -561
  64. build/lib/moat/kv/exceptions.py +0 -126
  65. build/lib/moat/kv/mock/__init__.py +0 -101
  66. build/lib/moat/kv/mock/mqtt.py +0 -159
  67. build/lib/moat/kv/mock/tracer.py +0 -63
  68. build/lib/moat/kv/model.py +0 -1069
  69. build/lib/moat/kv/obj/__init__.py +0 -646
  70. build/lib/moat/kv/obj/command.py +0 -241
  71. build/lib/moat/kv/runner.py +0 -1347
  72. build/lib/moat/kv/server.py +0 -2809
  73. build/lib/moat/kv/types.py +0 -513
  74. ci/rtd-requirements.txt +0 -4
  75. ci/test-requirements.txt +0 -7
  76. ci/travis.sh +0 -96
  77. debian/.gitignore +0 -7
  78. debian/changelog +0 -1435
  79. debian/control +0 -43
  80. debian/moat-kv/usr/lib/python3/dist-packages/docs/source/conf.py +0 -201
  81. debian/moat-kv/usr/lib/python3/dist-packages/examples/pathify.py +0 -45
  82. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/__init__.py +0 -19
  83. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml +0 -93
  84. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_main.py +0 -91
  85. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/__init__.py +0 -98
  86. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/deletor.py +0 -139
  87. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/__init__.py +0 -444
  88. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/_test.py +0 -166
  89. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/password.py +0 -234
  90. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/root.py +0 -58
  91. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/__init__.py +0 -67
  92. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py +0 -71
  93. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/client.py +0 -1025
  94. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/code.py +0 -236
  95. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/codec.py +0 -11
  96. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/__init__.py +0 -1
  97. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/acl.py +0 -180
  98. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/auth.py +0 -261
  99. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/code.py +0 -293
  100. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/codec.py +0 -186
  101. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/data.py +0 -265
  102. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/dump/__init__.py +0 -143
  103. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/error.py +0 -149
  104. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/internal.py +0 -248
  105. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/job.py +0 -433
  106. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/log.py +0 -53
  107. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/server.py +0 -114
  108. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/type.py +0 -201
  109. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/config.py +0 -46
  110. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/data.py +0 -216
  111. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/errors.py +0 -561
  112. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/exceptions.py +0 -126
  113. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/__init__.py +0 -101
  114. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/mqtt.py +0 -159
  115. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/tracer.py +0 -63
  116. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/model.py +0 -1069
  117. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/__init__.py +0 -646
  118. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/command.py +0 -241
  119. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/runner.py +0 -1347
  120. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/server.py +0 -2809
  121. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/types.py +0 -513
  122. debian/moat-kv.postinst +0 -3
  123. debian/rules +0 -20
  124. debian/source/format +0 -1
  125. debian/watch +0 -4
  126. docs/Makefile +0 -20
  127. docs/make.bat +0 -36
  128. docs/source/TODO.rst +0 -61
  129. docs/source/_static/.gitkeep +0 -0
  130. docs/source/acls.rst +0 -80
  131. docs/source/auth.rst +0 -84
  132. docs/source/client_protocol.rst +0 -456
  133. docs/source/code.rst +0 -341
  134. docs/source/command_line.rst +0 -1187
  135. docs/source/common_protocol.rst +0 -47
  136. docs/source/conf.py +0 -201
  137. docs/source/debugging.rst +0 -70
  138. docs/source/extend.rst +0 -37
  139. docs/source/history.rst +0 -36
  140. docs/source/index.rst +0 -75
  141. docs/source/model.rst +0 -54
  142. docs/source/overview.rst +0 -83
  143. docs/source/related.rst +0 -89
  144. docs/source/server_protocol.rst +0 -450
  145. docs/source/startup.rst +0 -31
  146. docs/source/translator.rst +0 -244
  147. docs/source/tutorial.rst +0 -711
  148. docs/source/v3.rst +0 -168
  149. examples/code/transform.scale.yml +0 -21
  150. examples/code/transform.switch.yml +0 -82
  151. examples/code/transform.timeslot.yml +0 -63
  152. examples/pathify.py +0 -45
  153. moat/kv/codec.py +0 -11
  154. moat_kv-0.71.0.dist-info/RECORD +0 -188
  155. moat_kv-0.71.0.dist-info/top_level.txt +0 -9
  156. scripts/current +0 -15
  157. scripts/env +0 -8
  158. scripts/init +0 -39
  159. scripts/recover +0 -17
  160. scripts/rotate +0 -33
  161. scripts/run +0 -29
  162. scripts/run-all +0 -10
  163. scripts/run-any +0 -10
  164. scripts/run-single +0 -15
  165. scripts/success +0 -4
  166. systemd/moat-kv-recover.service +0 -21
  167. systemd/moat-kv-rotate.service +0 -20
  168. systemd/moat-kv-rotate.timer +0 -10
  169. systemd/moat-kv-run-all.service +0 -26
  170. systemd/moat-kv-run-all@.service +0 -25
  171. systemd/moat-kv-run-any.service +0 -26
  172. systemd/moat-kv-run-any@.service +0 -25
  173. systemd/moat-kv-run-single.service +0 -26
  174. systemd/moat-kv-run-single@.service +0 -25
  175. systemd/moat-kv.service +0 -27
  176. systemd/postinst +0 -7
  177. systemd/sysusers +0 -3
  178. {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/licenses/LICENSE.txt +0 -0
moat/kv/data.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Data access
3
3
  """
4
+
4
5
  from __future__ import annotations
5
6
 
6
7
  import datetime
@@ -10,6 +11,8 @@ import time
10
11
  from collections.abc import Mapping
11
12
 
12
13
  from moat.util import NotGiven, Path, attrdict, process_args, yprint
14
+ from moat.util.times import ts2iso
15
+ import contextlib
13
16
 
14
17
 
15
18
  def add_dates(d):
@@ -36,10 +39,7 @@ def add_dates(d):
36
39
  _add(v)
37
40
  continue
38
41
  if start <= v <= stop:
39
- d[f"_{k}"] = datetime.datetime.fromtimestamp(v).isoformat(
40
- sep=" ",
41
- timespec="milliseconds",
42
- )
42
+ d[f"_{k}"] = ts2iso(v)
43
43
 
44
44
  _add(d)
45
45
 
@@ -66,7 +66,10 @@ async def data_get(
66
66
  device name. Returning ``None`` causes the entry to be skipped.
67
67
  """
68
68
  if path_mangle is None:
69
- path_mangle = lambda x: x
69
+
70
+ def path_mangle(x):
71
+ return x
72
+
70
73
  if item_mangle is None:
71
74
 
72
75
  async def item_mangle(x): # pylint: disable=function-redefined
@@ -199,10 +202,8 @@ async def node_attr(obj, path, res=None, chain=None, **kw):
199
202
  if res is None:
200
203
  res = await obj.client.get(path, nchain=obj.meta or 2)
201
204
  if chain is None:
202
- try:
205
+ with contextlib.suppress(AttributeError):
203
206
  chain = res.chain
204
- except AttributeError:
205
- pass
206
207
  try:
207
208
  val = res.value
208
209
  except AttributeError:
moat/kv/errors.py CHANGED
@@ -89,10 +89,11 @@ from weakref import WeakValueDictionary
89
89
 
90
90
  import anyio
91
91
  from moat.util import Cache, NotGiven, Path
92
+ from moat.lib.codec import get_codec
92
93
 
93
- from .codec import packer
94
94
  from .exceptions import ServerError
95
95
  from .obj import AttrClientEntry, ClientEntry, ClientRoot
96
+ import contextlib
96
97
 
97
98
  logger = logging.getLogger(__name__)
98
99
 
@@ -148,9 +149,11 @@ class ErrorEntry(AttrClientEntry):
148
149
  def __init__(self, *a, **kw):
149
150
  super().__init__(*a, **kw)
150
151
  self.node, self.tock = self.subpath[-2:]
152
+ if isinstance(self.path,list):
153
+ self.path=Path.build(self.path)
151
154
 
152
155
  def __repr__(self):
153
- return "<%s: %s %s: %s>" % (
156
+ return "<{}: {} {}: {}>".format(
154
157
  self.__class__.__name__,
155
158
  "/".join(str(x) for x in self.subpath),
156
159
  self.subsystem,
@@ -231,10 +234,11 @@ class ErrorEntry(AttrClientEntry):
231
234
  try:
232
235
  r = await res.save()
233
236
  except TypeError:
237
+ codec = get_codec("std-msgpack")
234
238
  for k in res.ATTRS:
235
239
  v = getattr(res, k, None)
236
240
  try:
237
- packer(v)
241
+ codec.encode(v)
238
242
  except TypeError:
239
243
  setattr(res, k, repr(v))
240
244
  r = await res.save()
@@ -404,6 +408,7 @@ class ErrorRoot(ClientRoot):
404
408
  must be filled and stored by the caller.
405
409
  """
406
410
 
411
+ path=Path.build(path)
407
412
  err = self._active[subsystem].get(path, None)
408
413
  if err is not None:
409
414
  return err
@@ -486,7 +491,7 @@ class ErrorRoot(ClientRoot):
486
491
  severity=0,
487
492
  message=None,
488
493
  force: bool = False,
489
- comment: str = None,
494
+ comment: str | None = None,
490
495
  ):
491
496
  """An exception has occurred for this subtype and path.
492
497
 
@@ -505,6 +510,8 @@ class ErrorRoot(ClientRoot):
505
510
  if not force and hasattr(rec, "severity") and rec.severity < severity:
506
511
  return rec
507
512
 
513
+ if isinstance(path,list):
514
+ path=Path.build(path)
508
515
  rec.severity = severity
509
516
  rec.subsystem = subsystem
510
517
  rec.path = path
@@ -544,10 +551,8 @@ class ErrorRoot(ClientRoot):
544
551
  if rec is not entry:
545
552
  return
546
553
 
547
- try:
554
+ with contextlib.suppress(KeyError):
548
555
  del (self._done if entry.resolved else self._active)[entry.subsystem][entry.path]
549
- except KeyError:
550
- pass
551
556
 
552
557
  def _push(self, entry):
553
558
  if entry.subsystem is None or entry.path is None:
@@ -558,4 +563,7 @@ class ErrorRoot(ClientRoot):
558
563
  self._latest.keep(entry)
559
564
  else:
560
565
  dest = self._active
561
- dest[entry.subsystem][entry.path] = entry
566
+ path=entry.path
567
+ if isinstance(path,list):
568
+ path=Path.build(path)
569
+ dest[entry.subsystem][path] = entry
moat/kv/mock/__init__.py CHANGED
@@ -1,28 +1,18 @@
1
1
  # from asyncclick.testing import CliRunner
2
2
  from __future__ import annotations
3
- import io
4
3
  import logging
5
- import shlex
6
4
  import socket
7
- import sys
8
- from pathlib import Path
9
5
 
10
6
  import attr
11
- from asyncscope import main_scope, scope
7
+ from asyncscope import scope
12
8
  from moat.src.test import run # pylint:disable=import-error,no-name-in-module
13
9
  from moat.util import ( # pylint:disable=no-name-in-module
14
10
  CFG,
15
- OptCtx,
16
- attrdict,
17
11
  combine_dict,
18
12
  ensure_cfg,
19
- list_ext,
20
- load_ext,
21
- wrap_main,
22
- yload,
23
13
  )
24
14
 
25
- from moat.kv.client import _scoped_client, client_scope
15
+ from moat.kv.client import _scoped_client
26
16
 
27
17
  logger = logging.getLogger(__name__)
28
18
  try:
moat/kv/model.py CHANGED
@@ -25,7 +25,7 @@ class NodeDataSkipped(Exception):
25
25
  self.node = node
26
26
 
27
27
  def __repr__(self):
28
- return "<%s:%s>" % (self.__class__.__name__, self.node)
28
+ return f"<{self.__class__.__name__}:{self.node}>"
29
29
 
30
30
 
31
31
  ConvNull = None # imported later, if/when needed
@@ -60,9 +60,8 @@ class Node:
60
60
  self.entries = {}
61
61
  cache[name] = self
62
62
  else:
63
- if tick is not None:
64
- if self.tick is None or self.tick < tick:
65
- self.tick = tick
63
+ if tick is not None and (self.tick is None or self.tick < tick):
64
+ self.tick = tick
66
65
  return self
67
66
 
68
67
  # pylint: disable=unused-argument
@@ -102,7 +101,7 @@ class Node:
102
101
  return item in self.entries
103
102
 
104
103
  def __repr__(self):
105
- return "<%s: %s @%s>" % (self.__class__.__name__, self.name, self.tick)
104
+ return f"<{self.__class__.__name__}: {self.name} @{self.tick}>"
106
105
 
107
106
  def seen(self, tick, entry=None, local=False):
108
107
  """An event with this tick was in the entry's chain.
@@ -316,13 +315,10 @@ class NodeSet(defaultdict):
316
315
  self[n] = r
317
316
 
318
317
  def __repr__(self):
319
- return "%s(%s)" % (type(self).__name__, dict.__repr__(self))
318
+ return f"{type(self).__name__}({dict.__repr__(self)})"
320
319
 
321
320
  def __bool__(self):
322
- for v in self.values():
323
- if v:
324
- return True
325
- return False
321
+ return any(v for v in self.values())
326
322
 
327
323
  def serialize(self):
328
324
  d = dict()
@@ -369,7 +365,7 @@ class NodeEvent:
369
365
 
370
366
  """
371
367
 
372
- def __init__(self, node: Node, tick: int = None, prev: NodeEvent = None):
368
+ def __init__(self, node: Node, tick: int | None = None, prev: NodeEvent = None):
373
369
  self.node = node
374
370
  if tick is None:
375
371
  tick = node.tick
@@ -553,7 +549,7 @@ class UpdateEvent:
553
549
  res = ""
554
550
  else:
555
551
  res = repr(self.event) + ": "
556
- return "<%s:%s%s: %s→%s>" % (
552
+ return "<{}:{}{}: {}→{}>".format(
557
553
  self.__class__.__name__,
558
554
  res,
559
555
  repr(self.entry),
@@ -792,14 +788,14 @@ class Entry:
792
788
 
793
789
  def __repr__(self):
794
790
  try:
795
- res = "<%s:%s" % (self.__class__.__name__, self.path)
791
+ res = f"<{self.__class__.__name__}:{self.path}"
796
792
  if self.chain is not None:
797
- res += "@%s" % (repr(self.chain),)
793
+ res += f"@{self.chain!r}"
798
794
  if self.data is not None:
799
- res += " =%s" % (repr(self.data),)
795
+ res += f" ={self.data!r}"
800
796
  res += ">"
801
797
  except Exception as exc:
802
- res = "<%s:%s" % (self.__class__.__name__, str(exc))
798
+ res = f"<{self.__class__.__name__}:{exc!s}"
803
799
  return res
804
800
 
805
801
  @property
@@ -876,7 +872,8 @@ class Entry:
876
872
  raise RuntimeError("huh?")
877
873
 
878
874
  if evt.event == self.chain:
879
- if self._data != evt.new_value:
875
+ if False and self._data != evt.new_value:
876
+ # codec diffs due to wrong accurracy
880
877
  logger.error(
881
878
  "Diff %r: has\n%r\nbut should have\n%r\n",
882
879
  evt.event,
@@ -897,21 +894,20 @@ class Entry:
897
894
  logger.info("New: %s :%s: %r", evt.event, evt.tock, evt_val)
898
895
  return
899
896
 
900
- if self._data is not NotGiven:
901
- if not (self.chain < evt.event):
897
+ if self._data is not NotGiven and not (self.chain < evt.event):
898
+ if not loading:
899
+ logger.warning("*** inconsistency ***")
900
+ logger.warning("Node: %s", self.path)
901
+ logger.warning("Current: %s :%s: %r", self.chain, self.tock, self._data)
902
+ logger.warning("New: %s :%s: %r", evt.event, evt.tock, evt_val)
903
+ if evt.tock < self.tock:
902
904
  if not loading:
903
- logger.warning("*** inconsistency ***")
904
- logger.warning("Node: %s", self.path)
905
- logger.warning("Current: %s :%s: %r", self.chain, self.tock, self._data)
906
- logger.warning("New: %s :%s: %r", evt.event, evt.tock, evt_val)
907
- if evt.tock < self.tock:
908
- if not loading:
909
- logger.warning("New value ignored")
910
- # also mark the new event's chain as superseded
911
- server.drop_old_event(self.chain, evt.event)
912
- return
913
- if not loading:
914
- logger.warning("New value used")
905
+ logger.warning("New value ignored")
906
+ # also mark the new event's chain as superseded
907
+ server.drop_old_event(self.chain, evt.event)
908
+ return
909
+ if not loading:
910
+ logger.warning("New value used")
915
911
 
916
912
  if chk is not None and evt_val is not NotGiven:
917
913
  chk.check_value(evt_val, self)
@@ -1030,9 +1026,9 @@ class Watcher:
1030
1026
 
1031
1027
  root: Entry = None
1032
1028
  q = None
1033
- q_len = 100
1029
+ q_len = 10000
1034
1030
 
1035
- def __init__(self, root: Entry, full: bool = False, q_len: int = None):
1031
+ def __init__(self, root: Entry, full: bool = False, q_len: int | None = None):
1036
1032
  self.root = root
1037
1033
  self.full = full
1038
1034
  if q_len is not None:
moat/kv/obj/__init__.py CHANGED
@@ -2,6 +2,7 @@
2
2
  Object interface to moat.kv data
3
3
 
4
4
  """
5
+
5
6
  from __future__ import annotations
6
7
 
7
8
  import heapq
@@ -27,6 +28,7 @@ from moat.util import (
27
28
  ensure_cfg,
28
29
  CFG,
29
30
  )
31
+ import contextlib
30
32
 
31
33
  __all__ = ["ClientEntry", "AttrClientEntry", "ClientRoot"]
32
34
 
@@ -364,10 +366,8 @@ class AttrClientEntry(ClientEntry):
364
366
  if value is not NotGiven and k in value:
365
367
  setattr(self, k, value[k])
366
368
  else:
367
- try:
369
+ with contextlib.suppress(AttributeError):
368
370
  delattr(self, k)
369
- except AttributeError:
370
- pass
371
371
 
372
372
  def get_value(self, skip_none=False, skip_empty=False):
373
373
  """
moat/kv/obj/command.py CHANGED
@@ -149,10 +149,10 @@ def std_command(cli, *a, **kw):
149
149
  else:
150
150
  vv = "-"
151
151
  elif isinstance(vv, dict):
152
- vv = " ".join("%s=%s" % (x, y) for x, y in sorted(vv.items()))
153
- print("%s %s %s" % (k, kk, vv), file=obj.stdout)
152
+ vv = " ".join(f"{x}={y}" for x, y in sorted(vv.items()))
153
+ print(f"{k} {kk} {vv}", file=obj.stdout)
154
154
  else:
155
- print("%s %s" % (k, v), file=obj.stdout)
155
+ print(f"{k} {v}", file=obj.stdout)
156
156
  if not cnt and ctx.obj.debug:
157
157
  print("exists, no data", file=sys.stderr)
158
158
  else:
moat/kv/runner.py CHANGED
@@ -3,11 +3,12 @@ This module's job is to run code, resp. to keep it running.
3
3
 
4
4
 
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  import time
9
10
  from collections.abc import Mapping
10
- from contextlib import AsyncExitStack, asynccontextmanager
11
+ from contextlib import AsyncExitStack, asynccontextmanager, suppress
11
12
  from weakref import ref
12
13
 
13
14
  import anyio
@@ -418,10 +419,8 @@ class CallAdmin:
418
419
  if "topic" in msg:
419
420
  # pylint:disable=attribute-defined-outside-init
420
421
  chg = cls(msg.get("raw", None))
421
- try:
422
+ with suppress(AttributeError):
422
423
  chg.value = msg.data
423
- except AttributeError:
424
- pass
425
424
  chg.path = Path.build(msg.topic)
426
425
  await self.runner.send_event(chg)
427
426
 
@@ -535,7 +534,7 @@ class RunnerEntry(AttrClientEntry):
535
534
  self._logger = logger_for(self._path)
536
535
 
537
536
  def __repr__(self):
538
- return "<%s %r:%r>" % (self.__class__.__name__, self.subpath, self.code)
537
+ return f"<{self.__class__.__name__} {self.subpath!r}:{self.code!r}>"
539
538
 
540
539
  @property
541
540
  def state(self):