moat-kv 0.71.0__py3-none-any.whl → 0.71.6__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 +29 -29
  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 +28 -32
  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 +8 -6
  25. {moat_kv-0.71.0.dist-info → moat_kv-0.71.6.dist-info}/METADATA +6 -2
  26. moat_kv-0.71.6.dist-info/RECORD +47 -0
  27. {moat_kv-0.71.0.dist-info → moat_kv-0.71.6.dist-info}/WHEEL +1 -1
  28. moat_kv-0.71.6.dist-info/licenses/LICENSE +3 -0
  29. moat_kv-0.71.6.dist-info/licenses/LICENSE.APACHE2 +202 -0
  30. moat_kv-0.71.6.dist-info/licenses/LICENSE.MIT +20 -0
  31. moat_kv-0.71.6.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.6.dist-info}/licenses/LICENSE.txt +0 -0
moat/kv/__init__.py CHANGED
@@ -1,19 +1,18 @@
1
1
  # pylint: disable=W0703,C0103
2
2
  from __future__ import annotations
3
+ import contextlib
3
4
 
4
5
  __path__ = __import__("pkgutil").extend_path(__path__, __name__)
5
6
 
6
7
  try:
7
- import warning
8
- import pkg_resources # part of setuptools
9
-
10
- with warnings.filterwarnings("ignore"):
11
- _version = pkg_resources.require("moat.kv")[0].version
12
- del pkg_resources
13
- del warnings
8
+ from importlib.metadata import version
14
9
 
10
+ _version = version("moat.kv")
15
11
  _version_tuple = tuple(int(x) for x in _version.split("."))
16
12
 
17
13
  except Exception: # pragma: no cover
18
14
  _version = "0.0.1"
19
15
  _version_tuple = (0, 0, 1)
16
+
17
+ with contextlib.suppress(NameError):
18
+ del version
moat/kv/_cfg.yaml CHANGED
@@ -21,9 +21,9 @@ modules:
21
21
  prefix: !P :.moat.kv.code.module
22
22
  runner: # for moat.kv.runner.RunnerRoot
23
23
  # storage for runnable commands
24
- prefix: !P :.moat.kv.run"
24
+ prefix: !P :.moat.kv.run
25
25
  # storage for runner states
26
- state: !P :.moat.kv.state"
26
+ state: !P :.moat.kv.state
27
27
 
28
28
  name: "run"
29
29
 
@@ -55,6 +55,7 @@ server:
55
55
  # default
56
56
  mqtt:
57
57
  uri: "mqtt://localhost:1883"
58
+ codec: std-msgpack
58
59
 
59
60
  # event message path/topic prefix
60
61
  root: !P moat.kv
moat/kv/actor/__init__.py CHANGED
@@ -2,6 +2,7 @@
2
2
  This module implements a :class:`asyncactor.Actor` which works on top of
3
3
  a MoaT-KV client.
4
4
  """
5
+
5
6
  from __future__ import annotations
6
7
 
7
8
  from asyncactor import Actor
@@ -71,7 +72,7 @@ class ActorState:
71
72
  self.msg = msg
72
73
 
73
74
  def __repr__(self):
74
- return "<%s:%r>" % (self.__class__.__name__, self.msg)
75
+ return f"<{self.__class__.__name__}:{self.msg!r}>"
75
76
 
76
77
 
77
78
  class BrokenState(ActorState):
moat/kv/actor/deletor.py CHANGED
@@ -8,9 +8,12 @@ from __future__ import annotations
8
8
  import weakref
9
9
  from collections import deque
10
10
 
11
- import anyio
12
11
  from asyncactor import Actor, PingEvent, TagEvent
13
12
  from asyncactor.backend import get_transport
13
+ from typing import TYPE_CHECKING
14
+
15
+ if TYPE_CHECKING:
16
+ import anyio
14
17
 
15
18
  TAGS = 4
16
19
 
moat/kv/auth/__init__.py CHANGED
@@ -61,17 +61,20 @@ The server process is:
61
61
 
62
62
  from __future__ import annotations
63
63
 
64
- import io
65
64
  from importlib import import_module
66
65
 
67
66
  import jsonschema
68
67
  from moat.util import NotGiven, Path, attrdict, split_arg, yload
69
68
 
70
- from ..client import Client, NoData
71
- from ..exceptions import NoAuthModuleError
72
- from ..model import Entry
73
- from ..server import ServerClient, StreamCommand
74
- from ..types import ACLFinder, NullACL
69
+ from moat.kv.client import Client, NoData
70
+ from moat.kv.exceptions import NoAuthModuleError
71
+ from moat.kv.types import ACLFinder, NullACL
72
+ import contextlib
73
+ from typing import TYPE_CHECKING
74
+
75
+ if TYPE_CHECKING:
76
+ from moat.kv.server import ServerClient, StreamCommand
77
+ from moat.kv.model import Entry
75
78
 
76
79
  # Empty schema
77
80
  null_schema = {"type": "object", "additionalProperties": False}
@@ -211,7 +214,7 @@ class BaseClientAuth(_AuthLoaded):
211
214
  """
212
215
  Authorizes this record with the server.
213
216
  """
214
- try:
217
+ with contextlib.suppress(NoData):
215
218
  await client._request(
216
219
  action="auth",
217
220
  typ=self._auth_method,
@@ -220,8 +223,6 @@ class BaseClientAuth(_AuthLoaded):
220
223
  ident=self.ident,
221
224
  data=self.auth_data(),
222
225
  )
223
- except NoData:
224
- pass
225
226
 
226
227
  def auth_data(self):
227
228
  """
@@ -293,7 +294,7 @@ class BaseClientAuthMaker(_AuthLoaded):
293
294
 
294
295
  async def send(self, client: Client, _kind="user"):
295
296
  """Send this user to the server."""
296
- try:
297
+ with contextlib.suppress(NoData):
297
298
  await client._request(
298
299
  "auth_set",
299
300
  iter=False,
@@ -303,8 +304,6 @@ class BaseClientAuthMaker(_AuthLoaded):
303
304
  chain=self._chain,
304
305
  data=self.send_data(),
305
306
  )
306
- except NoData:
307
- pass
308
307
 
309
308
  def send_data(self):
310
309
  return {}
@@ -340,7 +339,7 @@ class BaseServerAuth(_AuthLoaded):
340
339
  jsonschema.validate(instance=data.get("data", {}), schema=type(self).schema)
341
340
 
342
341
  def aux_conv(self, data: Entry, root: Entry):
343
- from ..types import ConvNull
342
+ from moat.kv.types import ConvNull
344
343
 
345
344
  try:
346
345
  data = data["conv"].data["key"]
moat/kv/auth/_test.py CHANGED
@@ -11,7 +11,6 @@ import logging
11
11
 
12
12
  log = logging.getLogger(__name__)
13
13
 
14
- from ..client import Client
15
14
  from . import (
16
15
  BaseClientAuth,
17
16
  BaseClientAuthMaker,
@@ -20,6 +19,10 @@ from . import (
20
19
  null_client_login,
21
20
  null_server_login,
22
21
  )
22
+ from typing import TYPE_CHECKING
23
+
24
+ if TYPE_CHECKING:
25
+ from moat.kv.client import Client
23
26
 
24
27
 
25
28
  def load(typ: str, *, make: bool = False, server: bool):
moat/kv/auth/password.py CHANGED
@@ -9,10 +9,8 @@ from __future__ import annotations
9
9
 
10
10
  import nacl.secret
11
11
 
12
- from ..client import Client, NoData
13
- from ..exceptions import AuthFailedError
14
- from ..model import Entry
15
- from ..server import StreamCommand
12
+ from moat.kv.client import Client, NoData
13
+ from moat.kv.exceptions import AuthFailedError
16
14
  from . import (
17
15
  BaseClientAuth,
18
16
  BaseClientAuthMaker,
@@ -21,6 +19,12 @@ from . import (
21
19
  null_client_login,
22
20
  null_server_login,
23
21
  )
22
+ import contextlib
23
+ from typing import TYPE_CHECKING
24
+
25
+ if TYPE_CHECKING:
26
+ from moat.kv.server import StreamCommand
27
+ from moat.kv.model import Entry
24
28
 
25
29
 
26
30
  def load(typ: str, *, make: bool = False, server: bool):
@@ -57,6 +61,8 @@ async def pack_pwd(client, password, length):
57
61
  async def unpack_pwd(client, password):
58
62
  """Server side: extract password"""
59
63
  box = nacl.secret.SecretBox(client.dh_key)
64
+ if isinstance(password, memoryview):
65
+ password = bytes(password)
60
66
  pwd = box.decrypt(password)
61
67
  return pwd
62
68
  # TODO check with Argon2
@@ -164,10 +170,8 @@ class ClientUserMaker(BaseClientAuthMaker):
164
170
  # There's no reason to send the password hash back
165
171
  self = cls(_initial=_initial)
166
172
  self._name = m.name
167
- try:
173
+ with contextlib.suppress(AttributeError):
168
174
  self._chain = m.chain
169
- except AttributeError:
170
- pass
171
175
  return self
172
176
 
173
177
  async def send(self, client: Client, _kind="user", **msg): # pylint: disable=unused-argument,arguments-differ
moat/kv/backend/mqtt.py CHANGED
@@ -4,7 +4,6 @@ from contextlib import asynccontextmanager
4
4
 
5
5
  import anyio
6
6
  from moat.mqtt.client import MQTTClient
7
- from moat.mqtt.codecs import NoopCodec
8
7
  from moat.util import NotGiven
9
8
 
10
9
  from . import Backend
@@ -36,11 +35,11 @@ class MqttBackend(Backend):
36
35
  await C.disconnect()
37
36
 
38
37
  @asynccontextmanager
39
- async def monitor(self, *topic):
38
+ async def monitor(self, *topic, codec=NotGiven):
40
39
  topic = "/".join(str(x) for x in topic)
41
40
  logger.info("Monitor %s start", topic)
42
41
  try:
43
- async with self.client.subscription(topic) as sub:
42
+ async with self.client.subscription(topic, codec=codec) as sub:
44
43
 
45
44
  async def sub_get(sub):
46
45
  async for msg in sub:
@@ -55,12 +54,12 @@ class MqttBackend(Backend):
55
54
  else:
56
55
  logger.info("Monitor %s end", topic)
57
56
 
58
- def send(self, *topic, payload): # pylint: disable=invalid-overridden-method
57
+ def send(self, *topic, payload, **kw): # pylint: disable=invalid-overridden-method
59
58
  """
60
59
  Send this payload to this topic.
61
60
  """
62
61
  # client.publish is also async, pass-thru
63
- return self.client.publish("/".join(str(x) for x in topic), message=payload)
62
+ return self.client.publish("/".join(str(x) for x in topic), message=payload, **kw)
64
63
 
65
64
 
66
65
  @asynccontextmanager
moat/kv/client.py CHANGED
@@ -7,13 +7,13 @@ Main entry point: :func:`open_client`.
7
7
  from __future__ import annotations
8
8
 
9
9
  import logging
10
- import os
11
10
  import socket
12
- from contextlib import AsyncExitStack, asynccontextmanager
11
+ from contextlib import AsyncExitStack, asynccontextmanager, suppress
13
12
  from inspect import iscoroutine
14
13
 
15
14
  import anyio
16
15
  from asyncscope import Scope, main_scope, scope
16
+ from moat.lib.codec import get_codec
17
17
  from moat.util import ( # pylint: disable=no-name-in-module
18
18
  CFG,
19
19
  DelayedRead,
@@ -28,11 +28,11 @@ from moat.util import ( # pylint: disable=no-name-in-module
28
28
  create_queue,
29
29
  ensure_cfg,
30
30
  gen_ssl,
31
- gen_ident,al_lower,
31
+ gen_ident,
32
+ al_lower,
32
33
  num2byte,
33
34
  )
34
35
 
35
- from .codec import packer, stream_unpacker
36
36
  from .exceptions import (
37
37
  CancelledError,
38
38
  ClientAuthMethodError,
@@ -50,13 +50,6 @@ ClosedResourceError = anyio.ClosedResourceError
50
50
  __all__ = ["NoData", "ManyData", "open_client", "client_scope", "StreamedRequest"]
51
51
 
52
52
 
53
- class AsyncValueEvent(ValueEvent):
54
- def cancel(self):
55
- if self.scope is not None:
56
- self.scope.cancel()
57
- super().set_error(CancelledError())
58
-
59
-
60
53
  class NoData(ValueError):
61
54
  """No reply arrived"""
62
55
 
@@ -264,10 +257,8 @@ class StreamedRequest:
264
257
  except (anyio.BrokenResourceError, anyio.ClosedResourceError, EOFError):
265
258
  pass
266
259
  else:
267
- try:
260
+ with suppress(ServerClosedError):
268
261
  await self.aclose()
269
- except ServerClosedError:
270
- pass
271
262
 
272
263
  async def wait_started(self):
273
264
  await self._started.wait()
@@ -281,10 +272,8 @@ class StreamedRequest:
281
272
  if self._open:
282
273
  msg = dict(action="stop", task=self.seq)
283
274
  # self._client.logger.debug("SendC %s", msg)
284
- try:
275
+ with suppress(ServerClosedError, anyio.BrokenResourceError):
285
276
  await self._client._request(**msg, _async=True)
286
- except (ServerClosedError, anyio.BrokenResourceError):
287
- pass
288
277
  # ignore the reply
289
278
  finally:
290
279
  self.qr.close_sender()
@@ -301,7 +290,7 @@ class _SingleReply:
301
290
  def __init__(self, conn, seq, params):
302
291
  self._conn = conn
303
292
  self.seq = seq
304
- self.q = AsyncValueEvent()
293
+ self.q = ValueEvent()
305
294
  self._params = params
306
295
 
307
296
  async def set(self, msg):
@@ -401,6 +390,7 @@ class Client:
401
390
  ensure_cfg("moat.kv")
402
391
  self._cfg = combine_dict(cfg, CFG["kv"], cls=attrdict)
403
392
  self.config = ClientConfig(self)
393
+ self.codec = get_codec("std-msgpack")
404
394
 
405
395
  self._seq = 0
406
396
  self._handlers = {}
@@ -484,26 +474,24 @@ class Client:
484
474
  raise ServerClosedError("Disconnected")
485
475
 
486
476
  try:
487
- p = packer(params)
477
+ p = self.codec.encode(params)
488
478
  except TypeError as e:
489
479
  raise ValueError(f"Unable to pack: {params!r}") from e
490
480
  await sock.send(p)
491
481
 
492
482
  async def _reader(self, *, evt=None):
493
483
  """Main loop for reading"""
494
- unpacker = stream_unpacker()
495
-
496
484
  with anyio.CancelScope():
497
485
  # XXX store the scope so that the redaer may get cancelled?
498
486
  if evt is not None:
499
487
  await evt.set()
500
488
  try:
501
489
  while True:
502
- for msg in unpacker:
490
+ for msg in self.codec:
503
491
  # self.logger.debug("Recv %s", msg)
504
492
  try:
505
493
  await self._handle_msg(msg)
506
- except ClosedResourceError as exc:
494
+ except (ClosedResourceError,EOFError) as exc:
507
495
  logger.warning("Reader closed in handler", exc_info=exc)
508
496
  return
509
497
 
@@ -518,7 +506,7 @@ class Client:
518
506
  return # closed by us
519
507
  if len(buf) == 0: # Connection was closed.
520
508
  raise ServerClosedError("Connection closed by peer")
521
- unpacker.feed(buf)
509
+ self.codec.feed(buf)
522
510
 
523
511
  except BaseException as exc:
524
512
  logger.warning("Reader died: %r", exc, exc_info=exc)
@@ -554,7 +542,7 @@ class Client:
554
542
  Any other keywords are forwarded to the server.
555
543
  """
556
544
  if self._handlers is None:
557
- raise ClosedResourceError()
545
+ raise ClosedResourceError
558
546
  if seq is None:
559
547
  act = "action"
560
548
  self._seq += 1
@@ -612,7 +600,7 @@ class Client:
612
600
 
613
601
  async with client._stream("update", path=P("private.storage"),
614
602
  stream=True) as req:
615
- with MsgReader("/tmp/msgs.pack") as f:
603
+ with MsgReader("/tmp/msgs.pack",codec="std-cbor") as f:
616
604
  for msg in f:
617
605
  await req.send(msg)
618
606
  # … or …
@@ -647,17 +635,12 @@ class Client:
647
635
  yield res
648
636
  except BaseException as exc:
649
637
  if stream:
650
- try:
638
+ with suppress(anyio.ClosedResourceError):
651
639
  await res.send(error=repr(exc))
652
- except anyio.ClosedResourceError:
653
- pass
654
640
  raise
655
641
  finally:
656
- with anyio.fail_after(2, shield=True):
657
- try:
658
- await res.aclose()
659
- except anyio.ClosedResourceError:
660
- pass
642
+ with anyio.fail_after(2, shield=True), suppress(anyio.ClosedResourceError):
643
+ await res.aclose()
661
644
 
662
645
  async def _run_auth(self, auth=None):
663
646
  """
@@ -684,7 +667,7 @@ class Client:
684
667
  This async context manager handles the actual TCP connection to
685
668
  the MoaT-KV server.
686
669
  """
687
- hello = AsyncValueEvent()
670
+ hello = ValueEvent()
688
671
  self._handlers[0] = hello
689
672
 
690
673
  cfg = self._cfg["conn"]
@@ -737,10 +720,8 @@ class Client:
737
720
  yield self
738
721
  finally:
739
722
  # Clean up our hacked config
740
- try:
723
+ with suppress(AttributeError):
741
724
  del self._config
742
- except AttributeError:
743
- pass
744
725
  self.config = ClientConfig(self)
745
726
  finally:
746
727
  self._socket = None
@@ -1007,7 +988,7 @@ class Client:
1007
988
  """
1008
989
  return self._stream(action="msg_monitor", topic=topic, raw=raw)
1009
990
 
1010
- def msg_send(self, topic: tuple[str], data=None, raw: bytes = None):
991
+ def msg_send(self, topic: tuple[str], data=None, raw: bytes | None = None):
1011
992
  """
1012
993
  Tunnel a user-tagged message. This sends the message
1013
994
  to all active callers of :meth:`msg_monitor` which use the same topic.
moat/kv/code.py CHANGED
@@ -5,6 +5,7 @@ so that it can be called easily.
5
5
  "Code" consists of either Python modules or single procedures.
6
6
 
7
7
  """
8
+
8
9
  from __future__ import annotations
9
10
 
10
11
  import logging
@@ -15,6 +16,7 @@ import anyio
15
16
  from moat.util import NotGiven, P, make_module, make_proc
16
17
 
17
18
  from .obj import ClientEntry, ClientRoot
19
+ import contextlib
18
20
 
19
21
  logger = logging.getLogger(__name__)
20
22
 
@@ -81,10 +83,8 @@ class ModuleEntry(ClientEntry):
81
83
  await super().set_value(value)
82
84
  if value is NotGiven:
83
85
  self._module = None
84
- try:
86
+ with contextlib.suppress(KeyError):
85
87
  del sys.modules[self.name]
86
- except KeyError:
87
- pass
88
88
  return
89
89
 
90
90
  try:
moat/kv/command/data.py CHANGED
@@ -6,6 +6,7 @@ import time
6
6
 
7
7
  import asyncclick as click
8
8
  from moat.util import MsgReader, NotGiven, P, PathLongener, attr_args, yprint
9
+ from moat.util.times import ts2iso
9
10
 
10
11
  from moat.kv.client import StreamedRequest
11
12
  from moat.kv.data import add_dates, data_get, node_attr
@@ -244,8 +245,8 @@ async def monitor(obj, state, only, path_only, add_date, ignore):
244
245
  # value has been deleted
245
246
  continue
246
247
  if flushing:
247
- r["time"] = time.time()
248
- r["_time"] = datetime.datetime.now().isoformat(sep=" ", timespec="milliseconds")
248
+ r["time"] = ts = time.time()
249
+ r["_time"] = ts2iso(ts)
249
250
  yprint(r, stream=obj.stdout)
250
251
  print("---", file=obj.stdout)
251
252
  if flushing:
@@ -258,7 +259,7 @@ async def monitor(obj, state, only, path_only, add_date, ignore):
258
259
  @click.pass_obj
259
260
  async def update(obj, infile):
260
261
  """Send a list of updates to a MoaT-KV subtree"""
261
- async with MsgReader(path=infile) as reader:
262
+ async with MsgReader(path=infile, codec="std-msgpack") as reader:
262
263
  async for msg in reader:
263
264
  if not hasattr(msg, "path"):
264
265
  continue
@@ -6,19 +6,17 @@ import sys
6
6
  from collections.abc import Mapping
7
7
 
8
8
  import asyncclick as click
9
- from moat.mqtt.codecs import MsgPackCodec
10
9
  from moat.util import (
11
- MsgReader,
12
10
  MsgWriter,
13
11
  P,
14
12
  Path,
15
- PathLongener,
16
13
  load_subgroup,
17
14
  yload,
18
15
  yprint,
19
16
  )
20
17
 
21
- from moat.kv.codec import unpacker
18
+ from moat.util.mqtt import unpacker
19
+ from moat.util.msgpack import StdMsgpack
22
20
 
23
21
 
24
22
  @load_subgroup(short_help="Local data mangling", sub_pre="dump")
@@ -42,7 +40,7 @@ async def init(node, file):
42
40
  Using this command, followed by "moat kv server -l <outfile> <node>", is
43
41
  equivalent to running "moat kv server -i 'Initial data' <node>.
44
42
  """
45
- async with MsgWriter(path=file) as f:
43
+ async with MsgWriter(path=file, codec="std-msgpack") as f:
46
44
  await f(
47
45
  dict(
48
46
  chain=dict(node=node, tick=1, prev=None),
@@ -93,29 +91,31 @@ async def msg_(obj, path):
93
91
  be = obj.cfg.server.backend
94
92
  kw = obj.cfg.server[be]
95
93
 
96
- async with get_backend(be)(**kw) as conn:
97
- async with conn.monitor(*path) as stream:
98
- async for msg in stream:
99
- v = vars(msg)
100
- if isinstance(v.get("payload"), (bytearray, bytes)):
101
- t = msg.topic
102
- v = unpacker(v["payload"])
103
- v = _unpacker(v)
104
- if v is None:
105
- continue
106
- if not isinstance(v, Mapping):
107
- v = {"_data": v}
108
- v["_topic"] = Path.build(t)
109
- else:
110
- v["_type"] = type(msg).__name__
111
-
112
- v["_timestamp"] = datetime.datetime.now().isoformat(
113
- sep=" ",
114
- timespec="milliseconds",
115
- )
116
-
117
- yprint(v, stream=obj.stdout)
118
- print("---", file=obj.stdout)
94
+ async with (
95
+ get_backend(be)(**kw) as conn,
96
+ conn.monitor(*path) as stream,
97
+ ):
98
+ async for msg in stream:
99
+ v = vars(msg)
100
+ if isinstance(v.get("payload"), (bytearray, bytes)):
101
+ t = msg.topic
102
+ v = unpacker(v["payload"])
103
+ v = _unpacker(v)
104
+ if v is None:
105
+ continue
106
+ if not isinstance(v, Mapping):
107
+ v = {"_data": v}
108
+ v["_topic"] = Path.build(t)
109
+ else:
110
+ v["_type"] = type(msg).__name__
111
+
112
+ v["_timestamp"] = datetime.datetime.now().isoformat(
113
+ sep=" ",
114
+ timespec="milliseconds",
115
+ )
116
+
117
+ yprint(v, stream=obj.stdout)
118
+ print("---", file=obj.stdout)
119
119
 
120
120
 
121
121
  @cli.command("post")
@@ -137,7 +137,7 @@ async def post_(obj, path):
137
137
  be = obj.cfg.server.backend
138
138
  kw = obj.cfg.server[be]
139
139
 
140
- async with get_backend(be)(codec=MsgPackCodec, **kw) as conn:
140
+ async with get_backend(be)(codec=StdMsgpack(), **kw) as conn:
141
141
  for d in yload(sys.stdin, multi=True):
142
142
  topic = d.pop("_topic", path)
143
143
  await conn.send(*topic, payload=d)
@@ -6,6 +6,7 @@ from collections.abc import Mapping
6
6
  import asyncclick as click
7
7
  from moat.util import P, PathLongener, yprint
8
8
  from range_set import RangeSet
9
+ import contextlib
9
10
 
10
11
 
11
12
  @click.group(short_help="Control internal state.") # pylint: disable=undefined-variable
@@ -173,10 +174,8 @@ async def dump(obj, path):
173
174
  yy = y
174
175
  for p in path:
175
176
  yy = yy.setdefault(p, {})
176
- try:
177
+ with contextlib.suppress(KeyError):
177
178
  yy["_"] = r["value"]
178
- except KeyError:
179
- pass
180
179
  yprint(y, stream=obj.stdout)
181
180
 
182
181
 
moat/kv/command/job.py CHANGED
@@ -223,8 +223,7 @@ async def list_(obj, state, state_only, table, as_dict):
223
223
  st = "-stopped-"
224
224
  else:
225
225
  st = " | ".join(
226
- "%s %s"
227
- % (
226
+ "{} {}".format(
228
227
  Path.build(e.subpath)
229
228
  if e._path[-2] == ee._path[-1]
230
229
  else Path.build(ee.subpath),
moat/kv/command/type.py CHANGED
@@ -5,6 +5,7 @@ import json
5
5
 
6
6
  import asyncclick as click
7
7
  from moat.util import NotGiven, P, Path, PathLongener, yload, yprint
8
+ import contextlib
8
9
 
9
10
 
10
11
  @click.group() # pylint: disable=undefined-variable
@@ -134,10 +135,8 @@ async def match(obj, path, type_, delete, raw): # pylint: disable=redefined-bui
134
135
  yy = y
135
136
  for p in path:
136
137
  yy = yy.setdefault(p, {})
137
- try:
138
+ with contextlib.suppress(KeyError):
138
139
  yy["_"] = r["value"]
139
- except KeyError:
140
- pass
141
140
  yprint(y, stream=obj.stdout)
142
141
  return
143
142
 
@@ -194,8 +193,6 @@ async def list(obj, path): # pylint: disable=redefined-builtin
194
193
  yy = y
195
194
  for p in path:
196
195
  yy = yy.setdefault(p, {})
197
- try:
196
+ with contextlib.suppress(KeyError):
198
197
  yy["_"] = r["value"]
199
- except KeyError:
200
- pass
201
198
  yprint(y, stream=obj.stdout)