aprsd 4.2.1__py3-none-any.whl → 4.2.3__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.
aprsd/client/client.py CHANGED
@@ -10,14 +10,14 @@ from oslo_config import cfg
10
10
  from aprsd.client import drivers # noqa - ensure drivers are registered
11
11
  from aprsd.client.drivers.registry import DriverRegistry
12
12
  from aprsd.packets import core
13
- from aprsd.utils import keepalive_collector
13
+ from aprsd.utils import keepalive_collector, trace
14
14
 
15
15
  CONF = cfg.CONF
16
16
  LOG = logging.getLogger('APRSD')
17
17
  LOGU = logger
18
18
 
19
19
 
20
- class APRSDClient:
20
+ class APRSDClient(metaclass=trace.TraceWrapperMetaclass):
21
21
  """APRSD client class.
22
22
 
23
23
  This is a singleton class that provides a single instance of the APRSD client.
@@ -41,11 +41,13 @@ class APRSDClient:
41
41
  def __init__(self, auto_connect: bool = True):
42
42
  self.auto_connect = auto_connect
43
43
  self.connected = False
44
+ self.running = False
44
45
  self.login_status = {
45
46
  'success': False,
46
47
  'message': None,
47
48
  }
48
- self.driver = DriverRegistry().get_driver()
49
+ if not self.driver:
50
+ self.driver = DriverRegistry().get_driver()
49
51
  if self.auto_connect:
50
52
  self.connect()
51
53
 
@@ -100,14 +102,20 @@ class APRSDClient:
100
102
  return self.driver.filter
101
103
 
102
104
  def is_alive(self):
103
- return self.driver.is_alive()
105
+ return self.driver.is_alive
104
106
 
107
+ @wrapt.synchronized(lock)
105
108
  def connect(self):
106
109
  if not self.driver:
107
110
  self.driver = DriverRegistry().get_driver()
108
- self.driver.setup_connection()
111
+ if not self.connected:
112
+ self.driver.setup_connection()
113
+ self.connected = self.driver.is_alive
114
+ self.running = True
109
115
 
110
116
  def close(self):
117
+ self.running = False
118
+ self.connected = False
111
119
  if not self.driver:
112
120
  return
113
121
  self.driver.close()
@@ -115,10 +123,10 @@ class APRSDClient:
115
123
  @wrapt.synchronized(lock)
116
124
  def reset(self):
117
125
  """Call this to force a rebuild/reconnect."""
118
- LOG.info('Resetting client connection.')
126
+ LOG.warning('Resetting client connection.')
119
127
  if self.driver:
120
128
  self.driver.close()
121
- if not self.delay_connect:
129
+ if self.auto_connect:
122
130
  self.driver.setup_connection()
123
131
  if self.filter:
124
132
  self.driver.set_filter(self.filter)
@@ -126,7 +134,11 @@ class APRSDClient:
126
134
  LOG.warning('Client not initialized, nothing to reset.')
127
135
 
128
136
  def send(self, packet: core.Packet) -> bool:
129
- return self.driver.send(packet)
137
+ if self.running:
138
+ return self.driver.send(packet)
139
+ else:
140
+ LOG.error('Client not running, not sending packet.')
141
+ return False
130
142
 
131
143
  # For the keepalive collector
132
144
  def keepalive_check(self):
@@ -145,7 +157,8 @@ class APRSDClient:
145
157
  LOGU.opt(colors=True).info(f'<green>Client keepalive {keepalive}</green>')
146
158
 
147
159
  def consumer(self, callback: Callable, raw: bool = False):
148
- return self.driver.consumer(callback=callback, raw=raw)
160
+ if self.running:
161
+ return self.driver.consumer(callback=callback, raw=raw)
149
162
 
150
163
  def decode_packet(self, *args, **kwargs) -> core.Packet:
151
164
  try:
@@ -10,6 +10,7 @@ from oslo_config import cfg
10
10
  from aprsd import client, exception
11
11
  from aprsd.client.drivers.lib.aprslib import APRSLibClient
12
12
  from aprsd.packets import core
13
+ from aprsd.utils import singleton
13
14
 
14
15
  CONF = cfg.CONF
15
16
  LOG = logging.getLogger('APRSD')
@@ -17,6 +18,7 @@ LOGU = logger
17
18
 
18
19
 
19
20
  # class APRSISDriver(metaclass=trace.TraceWrapperMetaclass):
21
+ @singleton
20
22
  class APRSISDriver:
21
23
  """This is the APRS-IS driver for the APRSD client.
22
24
 
@@ -78,16 +80,18 @@ class APRSISDriver:
78
80
  if self._client:
79
81
  self._client.stop()
80
82
  self._client.close()
83
+ self.connected = False
81
84
 
82
85
  def send(self, packet: core.Packet) -> bool:
83
86
  return self._client.send(packet)
84
87
 
85
88
  def setup_connection(self):
89
+ if self.connected:
90
+ return
86
91
  user = CONF.aprs_network.login
87
92
  password = CONF.aprs_network.password
88
93
  host = CONF.aprs_network.host
89
94
  port = CONF.aprs_network.port
90
- self.connected = False
91
95
  backoff = 1
92
96
  retries = 3
93
97
  retry_count = 0
@@ -97,7 +101,7 @@ class APRSISDriver:
97
101
  break
98
102
  try:
99
103
  LOG.info(
100
- f'Creating aprslib client({host}:{port}) and logging in {user}.'
104
+ f'Creating aprslib client({host}:{port}) and logging in {user}. try #{retry_count}'
101
105
  )
102
106
  self._client = APRSLibClient(
103
107
  user, passwd=password, host=host, port=port
@@ -152,7 +156,7 @@ class APRSISDriver:
152
156
  def _is_stale_connection(self):
153
157
  delta = datetime.datetime.now() - self._client.aprsd_keepalive
154
158
  if delta > self.max_delta:
155
- LOG.error(f'Connection is stale, last heard {delta} ago.')
159
+ LOG.warning(f'Connection is stale, last heard {delta} ago.')
156
160
  return True
157
161
  return False
158
162
 
@@ -64,7 +64,7 @@ class APRSDFakeDriver(metaclass=trace.TraceWrapperMetaclass):
64
64
  return None
65
65
 
66
66
  @wrapt.synchronized(lock)
67
- def send(self, packet: core.Packet):
67
+ def send(self, packet: core.Packet) -> bool:
68
68
  """Send an APRS Message object."""
69
69
  LOG.info(f'Sending packet: {packet}')
70
70
  payload = None
@@ -84,6 +84,7 @@ class APRSDFakeDriver(metaclass=trace.TraceWrapperMetaclass):
84
84
  f"FAKE::Send '{payload}' TO '{packet.to_call}' From "
85
85
  f'\'{packet.from_call}\' with PATH "{self.path}"',
86
86
  )
87
+ return True
87
88
 
88
89
  def consumer(self, callback: Callable, raw: bool = False):
89
90
  LOG.debug('Start non blocking FAKE consumer')
@@ -20,6 +20,7 @@ class ClientDriver(Protocol):
20
20
  def is_configured(self) -> bool:
21
21
  pass
22
22
 
23
+ @property
23
24
  def is_alive(self) -> bool:
24
25
  pass
25
26
 
@@ -9,7 +9,6 @@ import datetime
9
9
  import logging
10
10
  import select
11
11
  import socket
12
- import time
13
12
  from typing import Any, Callable, Dict
14
13
 
15
14
  import aprslib
@@ -25,6 +24,7 @@ from aprsd import ( # noqa
25
24
  exception,
26
25
  )
27
26
  from aprsd.packets import core
27
+ from aprsd.utils import trace
28
28
 
29
29
  CONF = cfg.CONF
30
30
  LOG = logging.getLogger('APRSD')
@@ -46,10 +46,12 @@ def handle_fend(buffer: bytes, strip_df_start: bool = True) -> bytes:
46
46
  return bytes(frame)
47
47
 
48
48
 
49
- # class TCPKISSDriver(metaclass=trace.TraceWrapperMetaclass):
50
- class TCPKISSDriver:
49
+ class TCPKISSDriver(metaclass=trace.TraceWrapperMetaclass):
50
+ # class TCPKISSDriver:
51
51
  """APRSD client driver for TCP KISS connections."""
52
52
 
53
+ _instance = None
54
+
53
55
  # Class level attributes required by Client protocol
54
56
  packets_received = 0
55
57
  packets_sent = 0
@@ -62,6 +64,12 @@ class TCPKISSDriver:
62
64
  select_timeout = 1
63
65
  path = None
64
66
 
67
+ def __new__(cls, *args, **kwargs):
68
+ """This magic turns this into a singleton."""
69
+ if cls._instance is None:
70
+ cls._instance = super().__new__(cls)
71
+ return cls._instance
72
+
65
73
  def __init__(self):
66
74
  """Initialize the KISS client.
67
75
 
@@ -71,7 +79,6 @@ class TCPKISSDriver:
71
79
  super().__init__()
72
80
  self._connected = False
73
81
  self.keepalive = datetime.datetime.now()
74
- self._running = False
75
82
  # This is initialized in setup_connection()
76
83
  self.socket = None
77
84
 
@@ -111,7 +118,15 @@ class TCPKISSDriver:
111
118
 
112
119
  def close(self):
113
120
  """Close the connection."""
114
- self.stop()
121
+ self._connected = False
122
+ if self.socket:
123
+ try:
124
+ self.socket.close()
125
+ except Exception as e:
126
+ LOG.error(f'close: error closing socket: {e}')
127
+ pass
128
+ else:
129
+ LOG.warning('close: socket not initialized. no reason to close.')
115
130
 
116
131
  def send(self, packet: core.Packet):
117
132
  """Send an APRS packet.
@@ -163,6 +178,10 @@ class TCPKISSDriver:
163
178
  LOG.error('KISS is not enabled in configuration')
164
179
  return
165
180
 
181
+ if self._connected:
182
+ LOG.warning('KISS interface already connected')
183
+ return
184
+
166
185
  try:
167
186
  # Configure for TCP KISS
168
187
  if self.is_enabled():
@@ -217,22 +236,18 @@ class TCPKISSDriver:
217
236
  Raises:
218
237
  Exception: If not connected to KISS TNC
219
238
  """
220
- self._running = True
221
- while self._running:
222
- # Ensure connection
223
- if not self._connected:
224
- if not self.connect():
225
- time.sleep(1)
226
- continue
239
+ # Ensure connection
240
+ if not self._connected:
241
+ return
227
242
 
228
- # Read frame
229
- frame = self.read_frame()
230
- if frame:
231
- LOG.warning(f'GOT FRAME: {frame} calling {callback}')
232
- kwargs = {
233
- 'frame': frame,
234
- }
235
- callback(**kwargs)
243
+ # Read frame
244
+ frame = self.read_frame()
245
+ if frame:
246
+ LOG.info(f'GOT FRAME: {frame} calling {callback}')
247
+ kwargs = {
248
+ 'frame': frame,
249
+ }
250
+ callback(**kwargs)
236
251
 
237
252
  def decode_packet(self, *args, **kwargs) -> core.Packet:
238
253
  """Decode a packet from an AX.25 frame.
@@ -245,7 +260,6 @@ class TCPKISSDriver:
245
260
  LOG.warning('No frame received to decode?!?!')
246
261
  return None
247
262
 
248
- LOG.warning(f'FRAME: {str(frame)}')
249
263
  try:
250
264
  aprslib_frame = aprslib.parse(str(frame))
251
265
  packet = core.factory(aprslib_frame)
@@ -257,16 +271,6 @@ class TCPKISSDriver:
257
271
  LOG.error(f'Error decoding packet: {e}')
258
272
  return None
259
273
 
260
- def stop(self):
261
- """Stop the KISS interface."""
262
- self._running = False
263
- self._connected = False
264
- if self.socket:
265
- try:
266
- self.socket.close()
267
- except Exception:
268
- pass
269
-
270
274
  def stats(self, serializable: bool = False) -> Dict[str, Any]:
271
275
  """Get client statistics.
272
276
 
@@ -353,13 +357,19 @@ class TCPKISSDriver:
353
357
  """
354
358
  Generator for complete lines, received from the server
355
359
  """
360
+ if not self.socket:
361
+ return None
362
+
363
+ if not self._connected:
364
+ return None
365
+
356
366
  try:
357
367
  self.socket.setblocking(0)
358
368
  except OSError as e:
359
369
  LOG.error(f'socket error when setblocking(0): {str(e)}')
360
370
  raise aprslib.ConnectionDrop('connection dropped') from e
361
371
 
362
- while self._running:
372
+ while self._connected:
363
373
  short_buf = b''
364
374
 
365
375
  try:
@@ -375,14 +385,14 @@ class TCPKISSDriver:
375
385
  else:
376
386
  continue
377
387
  except Exception as e:
388
+ # No need to log if we are not running.
389
+ # this happens when the client is stopped/closed.
378
390
  LOG.error(f'Error in read loop: {e}')
379
391
  self._connected = False
380
392
  break
381
393
 
382
394
  try:
383
- print('reading from socket')
384
395
  short_buf = self.socket.recv(1024)
385
- print(f'short_buf: {short_buf}')
386
396
  # sock.recv returns empty if the connection drops
387
397
  if not short_buf:
388
398
  if not blocking:
aprsd/main.py CHANGED
@@ -72,6 +72,7 @@ def main():
72
72
 
73
73
  def signal_handler(sig, frame):
74
74
  click.echo('signal_handler: called')
75
+ collector.Collector().stop_all()
75
76
  threads.APRSDThreadList().stop_all()
76
77
  if 'subprocess' not in str(frame):
77
78
  LOG.info(
aprsd/stats/collector.py CHANGED
@@ -44,3 +44,9 @@ class Collector:
44
44
  if not isinstance(producer_name, StatsProducer):
45
45
  raise TypeError(f'Producer {producer_name} is not a StatsProducer')
46
46
  self.producers.remove(producer_name)
47
+
48
+ def stop_all(self):
49
+ """Stop and unregister all registered stats producers."""
50
+ for producer in self.producers[:]:
51
+ LOG.info(f'Stopping Stats producer {producer}')
52
+ self.unregister_producer(producer)
aprsd/utils/trace.py CHANGED
@@ -5,11 +5,11 @@ import logging
5
5
  import time
6
6
  import types
7
7
 
8
- VALID_TRACE_FLAGS = {"method", "api"}
8
+ VALID_TRACE_FLAGS = {'method', 'api'}
9
9
  TRACE_API = False
10
10
  TRACE_METHOD = False
11
11
  TRACE_ENABLED = False
12
- LOG = logging.getLogger("APRSD")
12
+ LOG = logging.getLogger('APRSD')
13
13
 
14
14
 
15
15
  def trace(*dec_args, **dec_kwargs):
@@ -27,11 +27,12 @@ def trace(*dec_args, **dec_kwargs):
27
27
 
28
28
  def _decorator(f):
29
29
  func_name = f.__qualname__
30
- func_file = "/".join(f.__code__.co_filename.split("/")[-4:])
30
+ func_file = '/'.join(f.__code__.co_filename.split('/')[-4:])
31
+ func_line_number = f.__code__.co_firstlineno
31
32
 
32
33
  @functools.wraps(f)
33
34
  def trace_logging_wrapper(*args, **kwargs):
34
- filter_function = dec_kwargs.get("filter_function")
35
+ filter_function = dec_kwargs.get('filter_function')
35
36
  logger = LOG
36
37
 
37
38
  # NOTE(ameade): Don't bother going any further if DEBUG log level
@@ -40,16 +41,16 @@ def trace(*dec_args, **dec_kwargs):
40
41
  return f(*args, **kwargs)
41
42
 
42
43
  all_args = inspect.getcallargs(f, *args, **kwargs)
43
-
44
44
  pass_filter = filter_function is None or filter_function(all_args)
45
45
 
46
46
  if pass_filter:
47
47
  logger.debug(
48
- "==> %(func)s: call %(all_args)r file: %(file)s",
48
+ '==> %(func)s: call %(all_args)r file: %(file)s:%(line_number)d',
49
49
  {
50
- "func": func_name,
51
- "all_args": str(all_args),
52
- "file": func_file,
50
+ 'func': func_name,
51
+ 'all_args': str(all_args),
52
+ 'file': func_file,
53
+ 'line_number': func_line_number,
53
54
  },
54
55
  )
55
56
 
@@ -59,11 +60,11 @@ def trace(*dec_args, **dec_kwargs):
59
60
  except Exception as exc:
60
61
  total_time = int(round(time.time() * 1000)) - start_time
61
62
  logger.debug(
62
- "<== %(func)s: exception (%(time)dms) %(exc)r",
63
+ '<== %(func)s: exception (%(time)dms) %(exc)r',
63
64
  {
64
- "func": func_name,
65
- "time": total_time,
66
- "exc": exc,
65
+ 'func': func_name,
66
+ 'time': total_time,
67
+ 'exc': exc,
67
68
  },
68
69
  )
69
70
  raise
@@ -78,11 +79,11 @@ def trace(*dec_args, **dec_kwargs):
78
79
 
79
80
  if pass_filter:
80
81
  logger.debug(
81
- "<== %(func)s: return (%(time)dms) %(result)r",
82
+ '<== %(func)s: return (%(time)dms) %(result)r',
82
83
  {
83
- "func": func_name,
84
- "time": total_time,
85
- "result": mask_result,
84
+ 'func': func_name,
85
+ 'time': total_time,
86
+ 'result': mask_result,
86
87
  },
87
88
  )
88
89
  return result
@@ -174,7 +175,7 @@ def setup_tracing(trace_flags):
174
175
  except TypeError: # Handle when trace_flags is None or a test mock
175
176
  trace_flags = []
176
177
  for invalid_flag in set(trace_flags) - VALID_TRACE_FLAGS:
177
- LOG.warning("Invalid trace flag: %s", invalid_flag)
178
- TRACE_METHOD = "method" in trace_flags
179
- TRACE_API = "api" in trace_flags
178
+ LOG.warning('Invalid trace flag: %s', invalid_flag)
179
+ TRACE_METHOD = 'method' in trace_flags
180
+ TRACE_API = 'api' in trace_flags
180
181
  TRACE_ENABLED = True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aprsd
3
- Version: 4.2.1
3
+ Version: 4.2.3
4
4
  Summary: APRSd is a APRS-IS server that can be used to connect to APRS-IS and send and receive APRS packets.
5
5
  Author-email: Craig Lamparter <craig@craiger.org>, "Walter A. Boring IV" <waboring@hemna.com>, Emre Saglam <emresaglam@gmail.com>, Jason Martin <jhmartin@toger.us>, John <johng42@users.noreply.github.com>, Martiros Shakhzadyan <vrzh@vrzh.net>, Zoe Moore <zoenb@mailbox.org>, ranguli <hello@joshmurphy.ca>
6
6
  Maintainer-email: Craig Lamparter <craig@craiger.org>, "Walter A. Boring IV" <waboring@hemna.com>
@@ -1,17 +1,17 @@
1
1
  aprsd/__init__.py,sha256=ci_49KK2a4GXyxcM2lFZfNAOsBfXzh0yayIGQazw56I,687
2
2
  aprsd/cli_helper.py,sha256=mKHww_cStwFBThjntFylrSnF6n9jOPHlR8r9SsrCxdY,4605
3
3
  aprsd/exception.py,sha256=bzln7sP9USQ67tz5nQh6e4KMaS8X2uhPJMNVmCkKV30,679
4
- aprsd/main.py,sha256=sOzG4tKtm7FGxwvYWIwiPujzo5TV3F0cSkR7IWHlb8M,4719
4
+ aprsd/main.py,sha256=JDI8VUGvi8KSG4hH125OlvdXC4xtwyakU0cB2YHpTXA,4756
5
5
  aprsd/plugin.py,sha256=pdyvKhSugFo4vRy7VflnaZ-BKozGa3GTTAHErskW3WU,17848
6
6
  aprsd/plugin_utils.py,sha256=beXQ1n_YI38rqDwswtE8NjFwFzjpaeve9W_JotX1n1A,2544
7
7
  aprsd/client/__init__.py,sha256=lh7mKBoSo2Tt82QoqlAARGm4LY6ffsn7d8x6M4B7n9g,154
8
- aprsd/client/client.py,sha256=7Y79BDaD0S28lziTgD6xl9C4f6rRrOgLJXNx_c__Wa8,4430
8
+ aprsd/client/client.py,sha256=sTZaxduDyGYtBpxpOvYAGG6D6gz6CPsivou9eKnW0tw,4898
9
9
  aprsd/client/stats.py,sha256=dUqRZao04B2TTj9TGMSygdLHa3if3pEy86eK-fK4sj4,353
10
10
  aprsd/client/drivers/__init__.py,sha256=IWSSrAEMrJQzulCIAx-N7Du0HK9sQOXIh98aJRCtfdg,421
11
- aprsd/client/drivers/aprsis.py,sha256=8VhKjnfAfxaXdBLKvC4guTU2WQsdHAvIogoxHX57gxc,6651
12
- aprsd/client/drivers/fake.py,sha256=b3q9-4O9Gtd7XnEzgZ2NzR5Zv6szxKBe07nsXJXmSHw,3249
13
- aprsd/client/drivers/registry.py,sha256=AWDWqxjOYHDz8ow4fNSSJ7JR6Tgy1axG6r0I9Yk2nJ8,2213
14
- aprsd/client/drivers/tcpkiss.py,sha256=cjdVL88aeOst7tlxZ15ti5EBJNiXqvWHWFVrZMrk23Y,13527
11
+ aprsd/client/drivers/aprsis.py,sha256=DLtNgj1YAOiaHiALfHD6W-QF6JkzgQdmL7BmPXOa7KA,6763
12
+ aprsd/client/drivers/fake.py,sha256=iCe7zRJxL3giADSX6PMNMcasr9g4GpPNFSGhrKlgCeg,3277
13
+ aprsd/client/drivers/registry.py,sha256=vTKYTGAnVdBAyvCL51BadGFMNBsibzr9-xLPfXm_a9U,2227
14
+ aprsd/client/drivers/tcpkiss.py,sha256=begkOCkrd1g5JpuPGgY-EMiy3NcMxZaHaaWZqoCIQ5w,13817
15
15
  aprsd/client/drivers/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  aprsd/client/drivers/lib/aprslib.py,sha256=9KTEKlivGT1f1js-u-w1WNLhOs1kQxkr3COa1CI95oE,9439
17
17
  aprsd/cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -52,7 +52,7 @@ aprsd/plugins/version.py,sha256=NAPFKQ0lQqgjoDyTVy8tZcRGmdcJE_ZogRElDz27V2U,839
52
52
  aprsd/plugins/weather.py,sha256=XOspEoAumUb35TW2RYqjRV0lp6hrR_kOMIT41iEUGQQ,13399
53
53
  aprsd/stats/__init__.py,sha256=ltAtUiEvpokBEtOpq0sxpDGOLQT2evgeZSVBzDzjkSo,808
54
54
  aprsd/stats/app.py,sha256=axqMA137zKqU03yO8XI5f1QE8ajmr9YK0J9O9m4iSzo,1378
55
- aprsd/stats/collector.py,sha256=7nx_KSP_PUeuX5q8xJhsB9G_JfgQFCAvrPNzO7uK4FM,1502
55
+ aprsd/stats/collector.py,sha256=hIwJyw7P457NduqEzP0FPHEzf_HOuXepsBRmxiSCKKs,1743
56
56
  aprsd/threads/__init__.py,sha256=KPqAOhS4q995NCEWDnPCHiuu3guyuMZlyDUGx_h50z8,259
57
57
  aprsd/threads/aprsd.py,sha256=13AS7jAhcQBmTervBiADaC1Ins9C-6TrMDYjW1fQJkg,4794
58
58
  aprsd/threads/keepalive.py,sha256=E48_erNnqik5AAllMGx5gexAwPIaznCp0HCG45NltFw,3939
@@ -69,11 +69,11 @@ aprsd/utils/keepalive_collector.py,sha256=r0oKCpKPGsivOKTQkTfwcJRESqMfbNawCyqrcH
69
69
  aprsd/utils/objectstore.py,sha256=0OivUeagncWGH7eWjTwZhauf-etweTabp8Oykt0hoF4,3541
70
70
  aprsd/utils/package.py,sha256=BtyIT6F5tPTFIATy5zDtYnB2k-rSFey5K2t9RPGenck,5025
71
71
  aprsd/utils/ring_buffer.py,sha256=lWWuw7lEbc2URhqAJfRLjpXBDLiK6UUWzk3j2VFnERQ,1111
72
- aprsd/utils/trace.py,sha256=lIuDZHOjvWbL2IMJ2tN_XW4Ch8oe4uQ7uLGylUByli0,5687
73
- aprsd-4.2.1.dist-info/licenses/AUTHORS,sha256=fGZhgXFMCfDPbp0hHllwmPyfiKPobLNA3sJA3BMIJVE,22
74
- aprsd-4.2.1.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
75
- aprsd-4.2.1.dist-info/METADATA,sha256=TKX8daOdMLu42sayX71q88zaAZfCBy_e3gyjsBOsBeg,45583
76
- aprsd-4.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
77
- aprsd-4.2.1.dist-info/entry_points.txt,sha256=4fReoJUB-bFqOUK6eeXYYCvTdVLprL7KVH0hWQRP9eM,171
78
- aprsd-4.2.1.dist-info/top_level.txt,sha256=v1O96niUcJOTMh9aQnFRknbScJ6mMOwqurdbxeaeSjs,6
79
- aprsd-4.2.1.dist-info/RECORD,,
72
+ aprsd/utils/trace.py,sha256=3W4V14qg63x39l77H7iaCEacXd_otvz3oJKwbKqH_jM,5812
73
+ aprsd-4.2.3.dist-info/licenses/AUTHORS,sha256=fGZhgXFMCfDPbp0hHllwmPyfiKPobLNA3sJA3BMIJVE,22
74
+ aprsd-4.2.3.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
75
+ aprsd-4.2.3.dist-info/METADATA,sha256=PJmJ8nucsHVSdnJRPggmAhLIiKHqJWC0hLyEYiN6NHU,45583
76
+ aprsd-4.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
77
+ aprsd-4.2.3.dist-info/entry_points.txt,sha256=4fReoJUB-bFqOUK6eeXYYCvTdVLprL7KVH0hWQRP9eM,171
78
+ aprsd-4.2.3.dist-info/top_level.txt,sha256=v1O96niUcJOTMh9aQnFRknbScJ6mMOwqurdbxeaeSjs,6
79
+ aprsd-4.2.3.dist-info/RECORD,,
File without changes