runtimepy 5.4.3__py3-none-any.whl → 5.4.4__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.
runtimepy/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # =====================================
2
2
  # generator=datazen
3
3
  # version=3.1.4
4
- # hash=d1fd99eada85e38ef836802f8c0a3c50
4
+ # hash=5a37b52aedb2af82fb174fbea8ce0c1f
5
5
  # =====================================
6
6
 
7
7
  """
@@ -10,7 +10,7 @@ Useful defaults and other package metadata.
10
10
 
11
11
  DESCRIPTION = "A framework for implementing Python services."
12
12
  PKG_NAME = "runtimepy"
13
- VERSION = "5.4.3"
13
+ VERSION = "5.4.4"
14
14
 
15
15
  # runtimepy-specific content.
16
16
  METRICS_NAME = "metrics"
@@ -21,6 +21,7 @@ from runtimepy.net.udp.tftp.base import (
21
21
  DEFAULT_TIMEOUT_S,
22
22
  REEMIT_PERIOD_S,
23
23
  BaseTftpConnection,
24
+ TftpErrorHandler,
24
25
  )
25
26
  from runtimepy.net.udp.tftp.enums import DEFAULT_MODE
26
27
  from runtimepy.util import PossiblePath, as_path
@@ -204,6 +205,7 @@ async def tftp(
204
205
  connection_kwargs: dict[str, Any] = None,
205
206
  timeout_s: float = DEFAULT_TIMEOUT_S,
206
207
  reemit_period_s: float = REEMIT_PERIOD_S,
208
+ error_handler: TftpErrorHandler = None,
207
209
  ) -> AsyncIterator[TftpConnection]:
208
210
  """Use a tftp connection as a managed context."""
209
211
 
@@ -218,6 +220,11 @@ async def tftp(
218
220
  conn = await TftpConnection.create_connection(
219
221
  remote_addr=(addr.name, addr.port), **connection_kwargs
220
222
  )
223
+
224
+ # Add error handlers.
225
+ if error_handler is not None:
226
+ conn.error_handlers.append(error_handler)
227
+
221
228
  async with conn.process_then_disable(**process_kwargs):
222
229
  # Set parameters.
223
230
  conn.endpoint_timeout.value = timeout_s
@@ -235,6 +242,7 @@ async def tftp_write(
235
242
  connection_kwargs: dict[str, Any] = None,
236
243
  timeout_s: float = DEFAULT_TIMEOUT_S,
237
244
  reemit_period_s: float = REEMIT_PERIOD_S,
245
+ error_handler: TftpErrorHandler = None,
238
246
  ) -> bool:
239
247
  """Attempt to perform a tftp write."""
240
248
 
@@ -244,6 +252,7 @@ async def tftp_write(
244
252
  connection_kwargs=connection_kwargs,
245
253
  timeout_s=timeout_s,
246
254
  reemit_period_s=reemit_period_s,
255
+ error_handler=error_handler,
247
256
  ) as conn:
248
257
  # Perform tftp interaction.
249
258
  result = await conn.request_write(
@@ -262,6 +271,7 @@ async def tftp_read(
262
271
  connection_kwargs: dict[str, Any] = None,
263
272
  timeout_s: float = DEFAULT_TIMEOUT_S,
264
273
  reemit_period_s: float = REEMIT_PERIOD_S,
274
+ error_handler: TftpErrorHandler = None,
265
275
  ) -> bool:
266
276
  """Attempt to perform a tftp read."""
267
277
 
@@ -271,6 +281,7 @@ async def tftp_read(
271
281
  connection_kwargs=connection_kwargs,
272
282
  timeout_s=timeout_s,
273
283
  reemit_period_s=reemit_period_s,
284
+ error_handler=error_handler,
274
285
  ) as conn:
275
286
  result = await conn.request_read(
276
287
  destination, filename, mode=mode, addr=addr
@@ -8,7 +8,7 @@ from contextlib import AsyncExitStack
8
8
  from io import BytesIO
9
9
  import logging
10
10
  from pathlib import Path
11
- from typing import BinaryIO, Union
11
+ from typing import BinaryIO, Callable, Union
12
12
 
13
13
  # third-party
14
14
  from vcorelib.math import metrics_time_ns
@@ -30,6 +30,8 @@ from runtimepy.primitives import Double, Uint16
30
30
  REEMIT_PERIOD_S = 0.20
31
31
  DEFAULT_TIMEOUT_S = 1.0
32
32
 
33
+ TftpErrorHandler = Callable[[TftpErrorCode, str, tuple[str, int]], None]
34
+
33
35
 
34
36
  class BaseTftpConnection(UdpConnection):
35
37
  """A class implementing a basic tftp interface."""
@@ -73,6 +75,7 @@ class BaseTftpConnection(UdpConnection):
73
75
 
74
76
  self.error_code = Uint16(time_source=metrics_time_ns)
75
77
  self.env.channel("error_code", self.error_code, enum="TftpErrorCode")
78
+ self.error_handlers: list[TftpErrorHandler] = []
76
79
 
77
80
  self.endpoint_period = Double(value=REEMIT_PERIOD_S)
78
81
  self.env.channel(
@@ -346,10 +349,14 @@ class BaseTftpConnection(UdpConnection):
346
349
  """Handle an error message."""
347
350
 
348
351
  # Update underlying primitive.
349
- error_code = self.error_code.from_stream(stream)
350
- self.endpoint(addr).handle_error(
351
- TftpErrorCode(error_code), stream.read().decode()
352
- )
352
+ error_code = TftpErrorCode(self.error_code.from_stream(stream))
353
+ message = stream.read().decode()
354
+
355
+ # Call extra error handlers.
356
+ for handler in self.error_handlers:
357
+ handler(error_code, message, addr)
358
+
359
+ self.endpoint(addr).handle_error(error_code, message)
353
360
 
354
361
  async def process_datagram(
355
362
  self, data: bytes, addr: tuple[str, int]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: runtimepy
3
- Version: 5.4.3
3
+ Version: 5.4.4
4
4
  Summary: A framework for implementing Python services.
5
5
  Home-page: https://github.com/vkottler/runtimepy
6
6
  Author: Vaughn Kottler
@@ -17,10 +17,10 @@ Classifier: License :: OSI Approved :: MIT License
17
17
  Requires-Python: >=3.11
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
+ Requires-Dist: websockets
20
21
  Requires-Dist: vcorelib >=3.3.1
21
22
  Requires-Dist: svgen >=0.6.8
22
23
  Requires-Dist: psutil
23
- Requires-Dist: websockets
24
24
  Provides-Extra: test
25
25
  Requires-Dist: pylint ; extra == 'test'
26
26
  Requires-Dist: flake8 ; extra == 'test'
@@ -44,11 +44,11 @@ Requires-Dist: uvloop ; (sys_platform != "win32" and sys_platform != "cygwin") a
44
44
  =====================================
45
45
  generator=datazen
46
46
  version=3.1.4
47
- hash=76ca13ab011b845de4580fd0bc1f9deb
47
+ hash=dbac0e58214ea7e4abbe7161a3c64749
48
48
  =====================================
49
49
  -->
50
50
 
51
- # runtimepy ([5.4.3](https://pypi.org/project/runtimepy/))
51
+ # runtimepy ([5.4.4](https://pypi.org/project/runtimepy/))
52
52
 
53
53
  [![python](https://img.shields.io/pypi/pyversions/runtimepy.svg)](https://pypi.org/project/runtimepy/)
54
54
  ![Build Status](https://github.com/vkottler/runtimepy/workflows/Python%20Package/badge.svg)
@@ -1,4 +1,4 @@
1
- runtimepy/__init__.py,sha256=_OzprSplcibI12WvqExDf_PsXnZWlDNJh_jotslRyXw,390
1
+ runtimepy/__init__.py,sha256=baR2RhS2-y7ZXgCnsPoi2qZNQvYUTMTNIsSR2qKnRNg,390
2
2
  runtimepy/__main__.py,sha256=OPAed6hggoQdw-6QAR62mqLC-rCkdDhOq0wyeS2vDRI,332
3
3
  runtimepy/app.py,sha256=sTvatbsGZ2Hdel36Si_WUbNMtg9CzsJyExr5xjIcxDE,970
4
4
  runtimepy/dev_requirements.txt,sha256=j0dh11ztJAzfaUL0iFheGjaZj9ppDzmTkclTT8YKO8c,230
@@ -194,8 +194,8 @@ runtimepy/net/udp/connection.py,sha256=YtLty6iveVH6PQRODKriwR5Q6lFi0Ed4k0o5r0bgA
194
194
  runtimepy/net/udp/create.py,sha256=84YDfJbNBlN0ZwbNpvh6Dl7ZPecbZfmpjMNRRWcvJDk,2005
195
195
  runtimepy/net/udp/protocol.py,sha256=A4SRHf0CgcL2zDs1nAsGDqz0RxKBy1soS8wtNdS5S0I,1492
196
196
  runtimepy/net/udp/queue.py,sha256=DF-YscxQcGbGCYQLz_l_BMaSRfraZOhRwieTEdXLMds,637
197
- runtimepy/net/udp/tftp/__init__.py,sha256=mpRewPEqKeuFf5yRO1cY5H7fjFJhX6PskpqE7zNP2Sc,8741
198
- runtimepy/net/udp/tftp/base.py,sha256=FCrtpLdUFkQU4nkn5vJc6Gn5EsZauCf8eLhxx1r_vG8,11276
197
+ runtimepy/net/udp/tftp/__init__.py,sha256=C4YI06y-xwHphYBc68jXL35CrLVNzds3-tIhxTp1PWk,9081
198
+ runtimepy/net/udp/tftp/base.py,sha256=7nEgxv3j6ehqP8q2p769NjnkkMBOw3smt1XDqFBmdN4,11551
199
199
  runtimepy/net/udp/tftp/endpoint.py,sha256=so60LdPTG66N5tdhHhiX7j_TBHvNOTi4JIgLcg2MAm0,10890
200
200
  runtimepy/net/udp/tftp/enums.py,sha256=06juMd__pJZsyL8zO8p3hRucnOratt1qtz9zcxzMg4s,1579
201
201
  runtimepy/net/udp/tftp/io.py,sha256=w6cnUt-T-Ma6Vg8BWoRbsNnIWUv0HTY4am6bcLWxNJs,803
@@ -255,9 +255,9 @@ runtimepy/tui/task.py,sha256=nUZo9fuOC-k1Wpqdzkv9v1tQirCI28fZVgcC13Ijvus,1093
255
255
  runtimepy/tui/channels/__init__.py,sha256=evDaiIn-YS9uGhdo8ZGtP9VK1ek6sr_P1nJ9JuSET0o,4536
256
256
  runtimepy/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
257
257
  runtimepy/ui/controls.py,sha256=yvT7h3thbYaitsakcIAJ90EwKzJ4b-jnc6p3UuVf_XE,1241
258
- runtimepy-5.4.3.dist-info/LICENSE,sha256=okYCYhGsx_BlzvFdoNVBVpw_Cfb4SOqHA_VAARml4Hc,1071
259
- runtimepy-5.4.3.dist-info/METADATA,sha256=4KcLsxZe_Li3WlDrpo5j6DerKciyPt33S9mMXxrjty8,8152
260
- runtimepy-5.4.3.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
261
- runtimepy-5.4.3.dist-info/entry_points.txt,sha256=-btVBkYv7ybcopqZ_pRky-bEzu3vhbaG3W3Z7ERBiFE,51
262
- runtimepy-5.4.3.dist-info/top_level.txt,sha256=0jPmh6yqHyyJJDwEID-LpQly-9kQ3WRMjH7Lix8peLg,10
263
- runtimepy-5.4.3.dist-info/RECORD,,
258
+ runtimepy-5.4.4.dist-info/LICENSE,sha256=okYCYhGsx_BlzvFdoNVBVpw_Cfb4SOqHA_VAARml4Hc,1071
259
+ runtimepy-5.4.4.dist-info/METADATA,sha256=QwSQWMUYIK5S4grh2n898qjjXI_7gHHMFtU10gqAX7c,8152
260
+ runtimepy-5.4.4.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
261
+ runtimepy-5.4.4.dist-info/entry_points.txt,sha256=-btVBkYv7ybcopqZ_pRky-bEzu3vhbaG3W3Z7ERBiFE,51
262
+ runtimepy-5.4.4.dist-info/top_level.txt,sha256=0jPmh6yqHyyJJDwEID-LpQly-9kQ3WRMjH7Lix8peLg,10
263
+ runtimepy-5.4.4.dist-info/RECORD,,