aprsd 4.0.2__py3-none-any.whl → 4.1.1__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.
@@ -0,0 +1,58 @@
1
+ import logging
2
+ from typing import Callable, Protocol, runtime_checkable, Union, Dict
3
+
4
+ from aprsd.packets import core
5
+ from aprsd.utils import singleton
6
+
7
+ LOG = logging.getLogger("APRSD")
8
+
9
+
10
+ @runtime_checkable
11
+ class PacketFilterProtocol(Protocol):
12
+ """Protocol API for a packet filter class.
13
+ """
14
+ def filter(self, packet: type[core.Packet]) -> Union[type[core.Packet], None]:
15
+ """When we get a packet from the network.
16
+
17
+ Return a Packet object if the filter passes. Return None if the
18
+ Packet is filtered out.
19
+ """
20
+ ...
21
+
22
+
23
+ @singleton
24
+ class PacketFilter:
25
+
26
+ def __init__(self):
27
+ self.filters: Dict[str, Callable] = {}
28
+
29
+ def register(self, packet_filter: Callable) -> None:
30
+ if not isinstance(packet_filter, PacketFilterProtocol):
31
+ raise TypeError(f"class {packet_filter} is not a PacketFilterProtocol object")
32
+
33
+ if packet_filter not in self.filters:
34
+ self.filters[packet_filter] = packet_filter()
35
+
36
+ def unregister(self, packet_filter: Callable) -> None:
37
+ if not isinstance(packet_filter, PacketFilterProtocol):
38
+ raise TypeError(f"class {packet_filter} is not a PacketFilterProtocol object")
39
+ if packet_filter in self.filters:
40
+ del self.filters[packet_filter]
41
+
42
+ def filter(self, packet: type[core.Packet]) -> Union[type[core.Packet], None]:
43
+ """Run through each of the filters.
44
+
45
+ This will step through each registered filter class
46
+ and call filter on it.
47
+
48
+ If the filter object returns None, we are done filtering.
49
+ If the filter object returns the packet, we continue filtering.
50
+ """
51
+ for packet_filter in self.filters:
52
+ try:
53
+ if not self.filters[packet_filter].filter(packet):
54
+ LOG.debug(f"{self.filters[packet_filter].__class__.__name__} dropped {packet.__class__.__name__}:{packet.human_info}")
55
+ return None
56
+ except Exception as ex:
57
+ LOG.error(f"{packet_filter.__clas__.__name__} failed filtering packet {packet.__class__.__name__} : {ex}")
58
+ return packet
File without changes
@@ -0,0 +1,68 @@
1
+ import logging
2
+ from typing import Union
3
+
4
+ from oslo_config import cfg
5
+
6
+ from aprsd import packets
7
+ from aprsd.packets import core
8
+
9
+ CONF = cfg.CONF
10
+ LOG = logging.getLogger('APRSD')
11
+
12
+
13
+ class DupePacketFilter:
14
+ """This is a packet filter to detect duplicate packets.
15
+
16
+ This Uses the PacketList object to see if a packet exists
17
+ already. If it does exist in the PacketList, then we need to
18
+ check the flag on the packet to see if it's been processed before.
19
+ If the packet has been processed already within the allowed
20
+ timeframe, then it's a dupe.
21
+ """
22
+
23
+ def filter(self, packet: type[core.Packet]) -> Union[type[core.Packet], None]:
24
+ # LOG.debug(f"{self.__class__.__name__}.filter called for packet {packet}")
25
+ """Filter a packet out if it's already been seen and processed."""
26
+ if isinstance(packet, core.AckPacket):
27
+ # We don't need to drop AckPackets, those should be
28
+ # processed.
29
+ # Send the AckPacket to the queue for processing elsewhere.
30
+ return packet
31
+ else:
32
+ # Make sure we aren't re-processing the same packet
33
+ # For RF based APRS Clients we can get duplicate packets
34
+ # So we need to track them and not process the dupes.
35
+ pkt_list = packets.PacketList()
36
+ found = False
37
+ try:
38
+ # Find the packet in the list of already seen packets
39
+ # Based on the packet.key
40
+ found = pkt_list.find(packet)
41
+ if not packet.msgNo:
42
+ # If the packet doesn't have a message id
43
+ # then there is no reliable way to detect
44
+ # if it's a dupe, so we just pass it on.
45
+ # it shouldn't get acked either.
46
+ found = False
47
+ except KeyError:
48
+ found = False
49
+
50
+ if not found:
51
+ # We haven't seen this packet before, so we process it.
52
+ return packet
53
+
54
+ if not packet.processed:
55
+ # We haven't processed this packet through the plugins.
56
+ return packet
57
+ elif packet.timestamp - found.timestamp < CONF.packet_dupe_timeout:
58
+ # If the packet came in within N seconds of the
59
+ # Last time seeing the packet, then we drop it as a dupe.
60
+ LOG.warning(
61
+ f'Packet {packet.from_call}:{packet.msgNo} already tracked, dropping.'
62
+ )
63
+ else:
64
+ LOG.warning(
65
+ f'Packet {packet.from_call}:{packet.msgNo} already tracked '
66
+ f'but older than {CONF.packet_dupe_timeout} seconds. processing.',
67
+ )
68
+ return packet
@@ -0,0 +1,53 @@
1
+ import logging
2
+ from typing import Union
3
+
4
+ from oslo_config import cfg
5
+
6
+ from aprsd import packets
7
+ from aprsd.packets import core
8
+ from aprsd.utils import singleton
9
+
10
+ CONF = cfg.CONF
11
+ LOG = logging.getLogger('APRSD')
12
+
13
+
14
+ @singleton
15
+ class PacketTypeFilter:
16
+ """This filter is used to filter out packets that don't match a specific type.
17
+
18
+ To use this, register it with the PacketFilter class,
19
+ then instante it and call set_allow_list() with a list of packet types
20
+ you want to allow to pass the filtering. All other packets will be
21
+ filtered out.
22
+ """
23
+
24
+ filters = {
25
+ packets.Packet.__name__: packets.Packet,
26
+ packets.AckPacket.__name__: packets.AckPacket,
27
+ packets.BeaconPacket.__name__: packets.BeaconPacket,
28
+ packets.GPSPacket.__name__: packets.GPSPacket,
29
+ packets.MessagePacket.__name__: packets.MessagePacket,
30
+ packets.MicEPacket.__name__: packets.MicEPacket,
31
+ packets.ObjectPacket.__name__: packets.ObjectPacket,
32
+ packets.StatusPacket.__name__: packets.StatusPacket,
33
+ packets.ThirdPartyPacket.__name__: packets.ThirdPartyPacket,
34
+ packets.WeatherPacket.__name__: packets.WeatherPacket,
35
+ packets.UnknownPacket.__name__: packets.UnknownPacket,
36
+ }
37
+
38
+ allow_list = ()
39
+
40
+ def set_allow_list(self, filter_list):
41
+ tmp_list = []
42
+ for filter in filter_list:
43
+ LOG.warning(
44
+ f'Setting filter {filter} : {self.filters[filter]} to tmp {tmp_list}'
45
+ )
46
+ tmp_list.append(self.filters[filter])
47
+ self.allow_list = tuple(tmp_list)
48
+
49
+ def filter(self, packet: type[core.Packet]) -> Union[type[core.Packet], None]:
50
+ """Only allow packets of certain types to filter through."""
51
+ if self.allow_list:
52
+ if isinstance(packet, self.allow_list):
53
+ return packet
@@ -7,7 +7,7 @@ from aprsd.packets import core
7
7
  from aprsd.utils import objectstore
8
8
 
9
9
  CONF = cfg.CONF
10
- LOG = logging.getLogger("APRSD")
10
+ LOG = logging.getLogger('APRSD')
11
11
 
12
12
 
13
13
  class PacketList(objectstore.ObjectStoreMixin):
@@ -27,8 +27,8 @@ class PacketList(objectstore.ObjectStoreMixin):
27
27
 
28
28
  def _init_data(self):
29
29
  self.data = {
30
- "types": {},
31
- "packets": OrderedDict(),
30
+ 'types': {},
31
+ 'packets': OrderedDict(),
32
32
  }
33
33
 
34
34
  def rx(self, packet: type[core.Packet]):
@@ -37,11 +37,11 @@ class PacketList(objectstore.ObjectStoreMixin):
37
37
  self._total_rx += 1
38
38
  self._add(packet)
39
39
  ptype = packet.__class__.__name__
40
- type_stats = self.data["types"].setdefault(
40
+ type_stats = self.data['types'].setdefault(
41
41
  ptype,
42
- {"tx": 0, "rx": 0},
42
+ {'tx': 0, 'rx': 0},
43
43
  )
44
- type_stats["rx"] += 1
44
+ type_stats['rx'] += 1
45
45
 
46
46
  def tx(self, packet: type[core.Packet]):
47
47
  """Add a packet that was received."""
@@ -49,32 +49,32 @@ class PacketList(objectstore.ObjectStoreMixin):
49
49
  self._total_tx += 1
50
50
  self._add(packet)
51
51
  ptype = packet.__class__.__name__
52
- type_stats = self.data["types"].setdefault(
52
+ type_stats = self.data['types'].setdefault(
53
53
  ptype,
54
- {"tx": 0, "rx": 0},
54
+ {'tx': 0, 'rx': 0},
55
55
  )
56
- type_stats["tx"] += 1
56
+ type_stats['tx'] += 1
57
57
 
58
58
  def add(self, packet):
59
59
  with self.lock:
60
60
  self._add(packet)
61
61
 
62
62
  def _add(self, packet):
63
- if not self.data.get("packets"):
63
+ if not self.data.get('packets'):
64
64
  self._init_data()
65
- if packet.key in self.data["packets"]:
66
- self.data["packets"].move_to_end(packet.key)
67
- elif len(self.data["packets"]) == self.maxlen:
68
- self.data["packets"].popitem(last=False)
69
- self.data["packets"][packet.key] = packet
65
+ if packet.key in self.data['packets']:
66
+ self.data['packets'].move_to_end(packet.key)
67
+ elif len(self.data['packets']) == self.maxlen:
68
+ self.data['packets'].popitem(last=False)
69
+ self.data['packets'][packet.key] = packet
70
70
 
71
71
  def find(self, packet):
72
72
  with self.lock:
73
- return self.data["packets"][packet.key]
73
+ return self.data['packets'][packet.key]
74
74
 
75
75
  def __len__(self):
76
76
  with self.lock:
77
- return len(self.data["packets"])
77
+ return len(self.data['packets'])
78
78
 
79
79
  def total_rx(self):
80
80
  with self.lock:
@@ -87,17 +87,23 @@ class PacketList(objectstore.ObjectStoreMixin):
87
87
  def stats(self, serializable=False) -> dict:
88
88
  with self.lock:
89
89
  # Get last N packets directly using list slicing
90
- packets_list = list(self.data.get("packets", {}).values())
91
- pkts = packets_list[-CONF.packet_list_stats_maxlen :][::-1]
92
-
90
+ if CONF.packet_list_stats_maxlen >= 0:
91
+ packets_list = list(self.data.get('packets', {}).values())
92
+ pkts = packets_list[-CONF.packet_list_stats_maxlen :][::-1]
93
+ else:
94
+ # We have to copy here, because this get() results in a pointer
95
+ # to the packets internally here, which can change after this
96
+ # function returns, which would cause a problem trying to save
97
+ # the stats to disk.
98
+ pkts = self.data.get('packets', {}).copy()
93
99
  stats = {
94
- "total_tracked": self._total_rx
100
+ 'total_tracked': self._total_rx
95
101
  + self._total_tx, # Fixed typo: was rx + rx
96
- "rx": self._total_rx,
97
- "tx": self._total_tx,
98
- "types": self.data.get("types", {}), # Changed default from [] to {}
99
- "packet_count": len(self.data.get("packets", [])),
100
- "maxlen": self.maxlen,
101
- "packets": pkts,
102
+ 'rx': self._total_rx,
103
+ 'tx': self._total_tx,
104
+ 'types': self.data.get('types', {}), # Changed default from [] to {}
105
+ 'packet_count': len(self.data.get('packets', [])),
106
+ 'maxlen': self.maxlen,
107
+ 'packets': pkts,
102
108
  }
103
109
  return stats
aprsd/plugin.py CHANGED
@@ -17,24 +17,24 @@ from aprsd.packets import watch_list
17
17
 
18
18
  # setup the global logger
19
19
  CONF = cfg.CONF
20
- LOG = logging.getLogger("APRSD")
20
+ LOG = logging.getLogger('APRSD')
21
21
 
22
22
  CORE_MESSAGE_PLUGINS = [
23
- "aprsd.plugins.email.EmailPlugin",
24
- "aprsd.plugins.fortune.FortunePlugin",
25
- "aprsd.plugins.location.LocationPlugin",
26
- "aprsd.plugins.ping.PingPlugin",
27
- "aprsd.plugins.time.TimePlugin",
28
- "aprsd.plugins.weather.USWeatherPlugin",
29
- "aprsd.plugins.version.VersionPlugin",
23
+ 'aprsd.plugins.email.EmailPlugin',
24
+ 'aprsd.plugins.fortune.FortunePlugin',
25
+ 'aprsd.plugins.location.LocationPlugin',
26
+ 'aprsd.plugins.ping.PingPlugin',
27
+ 'aprsd.plugins.time.TimePlugin',
28
+ 'aprsd.plugins.weather.USWeatherPlugin',
29
+ 'aprsd.plugins.version.VersionPlugin',
30
30
  ]
31
31
 
32
32
  CORE_NOTIFY_PLUGINS = [
33
- "aprsd.plugins.notify.NotifySeenPlugin",
33
+ 'aprsd.plugins.notify.NotifySeenPlugin',
34
34
  ]
35
35
 
36
- hookspec = pluggy.HookspecMarker("aprsd")
37
- hookimpl = pluggy.HookimplMarker("aprsd")
36
+ hookspec = pluggy.HookspecMarker('aprsd')
37
+ hookimpl = pluggy.HookimplMarker('aprsd')
38
38
 
39
39
 
40
40
  class APRSDPluginSpec:
@@ -76,14 +76,14 @@ class APRSDPluginBase(metaclass=abc.ABCMeta):
76
76
  else:
77
77
  LOG.error(
78
78
  "Can't start thread {}:{}, Must be a child "
79
- "of aprsd.threads.APRSDThread".format(
79
+ 'of aprsd.threads.APRSDThread'.format(
80
80
  self,
81
81
  thread,
82
82
  ),
83
83
  )
84
84
  except Exception:
85
85
  LOG.error(
86
- "Failed to start threads for plugin {}".format(
86
+ 'Failed to start threads for plugin {}'.format(
87
87
  self,
88
88
  ),
89
89
  )
@@ -93,7 +93,7 @@ class APRSDPluginBase(metaclass=abc.ABCMeta):
93
93
  return self.message_counter
94
94
 
95
95
  def help(self) -> str:
96
- return "Help!"
96
+ return 'Help!'
97
97
 
98
98
  @abc.abstractmethod
99
99
  def setup(self):
@@ -147,10 +147,10 @@ class APRSDWatchListPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
147
147
  # make sure the timeout is set or this doesn't work
148
148
  if watch_list:
149
149
  aprs_client = client.client_factory.create().client
150
- filter_str = "b/{}".format("/".join(watch_list))
150
+ filter_str = 'b/{}'.format('/'.join(watch_list))
151
151
  aprs_client.set_filter(filter_str)
152
152
  else:
153
- LOG.warning("Watch list enabled, but no callsigns set.")
153
+ LOG.warning('Watch list enabled, but no callsigns set.')
154
154
 
155
155
  @hookimpl
156
156
  def filter(self, packet: type[packets.Packet]) -> str | packets.MessagePacket:
@@ -164,7 +164,7 @@ class APRSDWatchListPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
164
164
  result = self.process(packet)
165
165
  except Exception as ex:
166
166
  LOG.error(
167
- "Plugin {} failed to process packet {}".format(
167
+ 'Plugin {} failed to process packet {}'.format(
168
168
  self.__class__,
169
169
  ex,
170
170
  ),
@@ -172,7 +172,7 @@ class APRSDWatchListPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
172
172
  if result:
173
173
  self.tx_inc()
174
174
  else:
175
- LOG.warning(f"{self.__class__} plugin is not enabled")
175
+ LOG.warning(f'{self.__class__} plugin is not enabled')
176
176
 
177
177
  return result
178
178
 
@@ -196,7 +196,7 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
196
196
  raise NotImplementedError
197
197
 
198
198
  def help(self):
199
- return "{}: {}".format(
199
+ return '{}: {}'.format(
200
200
  self.command_name.lower(),
201
201
  self.command_regex,
202
202
  )
@@ -207,7 +207,7 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
207
207
 
208
208
  @hookimpl
209
209
  def filter(self, packet: packets.MessagePacket) -> str | packets.MessagePacket:
210
- LOG.debug(f"{self.__class__.__name__} called")
210
+ LOG.debug(f'{self.__class__.__name__} called')
211
211
  if not self.enabled:
212
212
  result = f"{self.__class__.__name__} isn't enabled"
213
213
  LOG.warning(result)
@@ -215,7 +215,7 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
215
215
 
216
216
  if not isinstance(packet, packets.MessagePacket):
217
217
  LOG.warning(
218
- f"{self.__class__.__name__} Got a {packet.__class__.__name__} ignoring"
218
+ f'{self.__class__.__name__} Got a {packet.__class__.__name__} ignoring'
219
219
  )
220
220
  return packets.NULL_MESSAGE
221
221
 
@@ -237,7 +237,7 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
237
237
  result = self.process(packet)
238
238
  except Exception as ex:
239
239
  LOG.error(
240
- "Plugin {} failed to process packet {}".format(
240
+ 'Plugin {} failed to process packet {}'.format(
241
241
  self.__class__,
242
242
  ex,
243
243
  ),
@@ -254,7 +254,7 @@ class APRSFIKEYMixin:
254
254
 
255
255
  def ensure_aprs_fi_key(self):
256
256
  if not CONF.aprs_fi.apiKey:
257
- LOG.error("Config aprs_fi.apiKey is not set")
257
+ LOG.error('Config aprs_fi.apiKey is not set')
258
258
  self.enabled = False
259
259
  else:
260
260
  self.enabled = True
@@ -266,25 +266,25 @@ class HelpPlugin(APRSDRegexCommandPluginBase):
266
266
  This plugin is in this file to prevent a circular import.
267
267
  """
268
268
 
269
- command_regex = "^[hH]"
270
- command_name = "help"
269
+ command_regex = '^[hH]'
270
+ command_name = 'help'
271
271
 
272
272
  def help(self):
273
- return "Help: send APRS help or help <plugin>"
273
+ return 'Help: send APRS help or help <plugin>'
274
274
 
275
275
  def process(self, packet: packets.MessagePacket):
276
- LOG.info("HelpPlugin")
276
+ LOG.info('HelpPlugin')
277
277
  # fromcall = packet.get("from")
278
278
  message = packet.message_text
279
279
  # ack = packet.get("msgNo", "0")
280
- a = re.search(r"^.*\s+(.*)", message)
280
+ a = re.search(r'^.*\s+(.*)', message)
281
281
  command_name = None
282
282
  if a is not None:
283
283
  command_name = a.group(1).lower()
284
284
 
285
285
  pm = PluginManager()
286
286
 
287
- if command_name and "?" not in command_name:
287
+ if command_name and '?' not in command_name:
288
288
  # user wants help for a specific plugin
289
289
  reply = None
290
290
  for p in pm.get_plugins():
@@ -303,20 +303,20 @@ class HelpPlugin(APRSDRegexCommandPluginBase):
303
303
  LOG.debug(p)
304
304
  if p.enabled and isinstance(p, APRSDRegexCommandPluginBase):
305
305
  name = p.command_name.lower()
306
- if name not in list and "help" not in name:
306
+ if name not in list and 'help' not in name:
307
307
  list.append(name)
308
308
 
309
309
  list.sort()
310
- reply = " ".join(list)
310
+ reply = ' '.join(list)
311
311
  lines = textwrap.wrap(reply, 60)
312
312
  replies = ["Send APRS MSG of 'help' or 'help <plugin>'"]
313
313
  for line in lines:
314
- replies.append(f"plugins: {line}")
314
+ replies.append(f'plugins: {line}')
315
315
 
316
316
  for entry in replies:
317
- LOG.debug(f"{len(entry)} {entry}")
317
+ LOG.debug(f'{len(entry)} {entry}')
318
318
 
319
- LOG.debug(f"{replies}")
319
+ LOG.debug(f'{replies}')
320
320
  return replies
321
321
 
322
322
 
@@ -341,17 +341,17 @@ class PluginManager:
341
341
  return cls._instance
342
342
 
343
343
  def _init(self):
344
- self._pluggy_pm = pluggy.PluginManager("aprsd")
344
+ self._pluggy_pm = pluggy.PluginManager('aprsd')
345
345
  self._pluggy_pm.add_hookspecs(APRSDPluginSpec)
346
346
  # For the watchlist plugins
347
- self._watchlist_pm = pluggy.PluginManager("aprsd")
347
+ self._watchlist_pm = pluggy.PluginManager('aprsd')
348
348
  self._watchlist_pm.add_hookspecs(APRSDPluginSpec)
349
349
 
350
350
  def stats(self, serializable=False) -> dict:
351
351
  """Collect and return stats for all plugins."""
352
352
 
353
353
  def full_name_with_qualname(obj):
354
- return "{}.{}".format(
354
+ return '{}.{}'.format(
355
355
  obj.__class__.__module__,
356
356
  obj.__class__.__qualname__,
357
357
  )
@@ -361,10 +361,10 @@ class PluginManager:
361
361
  if plugins:
362
362
  for p in plugins:
363
363
  plugin_stats[full_name_with_qualname(p)] = {
364
- "enabled": p.enabled,
365
- "rx": p.rx_count,
366
- "tx": p.tx_count,
367
- "version": p.version,
364
+ 'enabled': p.enabled,
365
+ 'rx': p.rx_count,
366
+ 'tx': p.tx_count,
367
+ 'version': p.version,
368
368
  }
369
369
 
370
370
  return plugin_stats
@@ -392,19 +392,19 @@ class PluginManager:
392
392
  module_name = None
393
393
  class_name = None
394
394
  try:
395
- module_name, class_name = module_class_string.rsplit(".", 1)
395
+ module_name, class_name = module_class_string.rsplit('.', 1)
396
396
  module = importlib.import_module(module_name)
397
397
  # Commented out because the email thread starts in a different context
398
398
  # and hence gives a different singleton for the EmailStats
399
399
  # module = importlib.reload(module)
400
400
  except Exception as ex:
401
401
  if not module_name:
402
- LOG.error(f"Failed to load Plugin {module_class_string}")
402
+ LOG.error(f'Failed to load Plugin {module_class_string}')
403
403
  else:
404
404
  LOG.error(f"Failed to load Plugin '{module_name}' : '{ex}'")
405
405
  return
406
406
 
407
- assert hasattr(module, class_name), "class {} is not in {}".format(
407
+ assert hasattr(module, class_name), 'class {} is not in {}'.format(
408
408
  class_name,
409
409
  module_name,
410
410
  )
@@ -412,7 +412,7 @@ class PluginManager:
412
412
  # class_name, module_name))
413
413
  cls = getattr(module, class_name)
414
414
  if super_cls is not None:
415
- assert issubclass(cls, super_cls), "class {} should inherit from {}".format(
415
+ assert issubclass(cls, super_cls), 'class {} should inherit from {}'.format(
416
416
  class_name,
417
417
  super_cls.__name__,
418
418
  )
@@ -444,7 +444,7 @@ class PluginManager:
444
444
  self._watchlist_pm.register(plugin_obj)
445
445
  else:
446
446
  LOG.warning(
447
- f"Plugin {plugin_obj.__class__.__name__} is disabled"
447
+ f'Plugin {plugin_obj.__class__.__name__} is disabled'
448
448
  )
449
449
  elif isinstance(plugin_obj, APRSDRegexCommandPluginBase):
450
450
  if plugin_obj.enabled:
@@ -458,7 +458,7 @@ class PluginManager:
458
458
  self._pluggy_pm.register(plugin_obj)
459
459
  else:
460
460
  LOG.warning(
461
- f"Plugin {plugin_obj.__class__.__name__} is disabled"
461
+ f'Plugin {plugin_obj.__class__.__name__} is disabled'
462
462
  )
463
463
  elif isinstance(plugin_obj, APRSDPluginBase):
464
464
  if plugin_obj.enabled:
@@ -471,7 +471,7 @@ class PluginManager:
471
471
  self._pluggy_pm.register(plugin_obj)
472
472
  else:
473
473
  LOG.warning(
474
- f"Plugin {plugin_obj.__class__.__name__} is disabled"
474
+ f'Plugin {plugin_obj.__class__.__name__} is disabled'
475
475
  )
476
476
  except Exception as ex:
477
477
  LOG.error(f"Couldn't load plugin '{plugin_name}'")
@@ -485,11 +485,11 @@ class PluginManager:
485
485
  def setup_plugins(
486
486
  self,
487
487
  load_help_plugin=True,
488
- plugin_list=[],
488
+ plugin_list=None,
489
489
  ):
490
490
  """Create the plugin manager and register plugins."""
491
491
 
492
- LOG.info("Loading APRSD Plugins")
492
+ LOG.info('Loading APRSD Plugins')
493
493
  # Help plugin is always enabled.
494
494
  if load_help_plugin:
495
495
  _help = HelpPlugin()
@@ -509,7 +509,7 @@ class PluginManager:
509
509
  for p_name in CORE_MESSAGE_PLUGINS:
510
510
  self._load_plugin(p_name)
511
511
 
512
- LOG.info("Completed Plugin Loading.")
512
+ LOG.info('Completed Plugin Loading.')
513
513
 
514
514
  def run(self, packet: packets.MessagePacket):
515
515
  """Execute all the plugins run method."""
@@ -524,7 +524,7 @@ class PluginManager:
524
524
  """Stop all threads created by all plugins."""
525
525
  with self.lock:
526
526
  for p in self.get_plugins():
527
- if hasattr(p, "stop_threads"):
527
+ if hasattr(p, 'stop_threads'):
528
528
  p.stop_threads()
529
529
 
530
530
  def register_msg(self, obj):