Lots of fixes

This commit is contained in:
Hemna 2021-01-08 15:47:30 -05:00
parent 4c0150dd97
commit 231c15b1af
17 changed files with 258 additions and 155 deletions

View File

@ -1,29 +1,48 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: fix-encoding-pragma
- id: detect-private-key
- id: check-merge-conflict
- id: check-case-conflict
- id: check-docstring-first
- id: check-builtin-literals
- repo: https://github.com/psf/black
rev: 19.3b0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: detect-private-key
- id: check-merge-conflict
- id: check-case-conflict
- id: check-docstring-first
- id: check-builtin-literals
- id: double-quote-string-fixer
- repo: https://github.com/pre-commit/mirrors-isort
rev: v5.7.0
hooks:
- id: isort
- repo: https://github.com/asottile/setup-cfg-fmt
rev: v1.16.0
hooks:
- id: setup-cfg-fmt
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.1
hooks:
- id: flake8
additional_dependencies: [flake8-bugbear]
- repo: https://github.com/asottile/add-trailing-comma
rev: v2.0.2
hooks:
- id: add-trailing-comma
args: [--py36-plus]
- repo: https://github.com/asottile/pyupgrade
rev: v2.7.4
hooks:
- id: pyupgrade
args:
- --py3-plus
- repo: https://github.com/pre-commit/mirrors-isort
rev: v5.7.0
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: 20.8b1
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.4
hooks:
- id: flake8
additional_dependencies: [flake8-bugbear]

View File

@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at

View File

@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-
import logging
import select
import socket
import time
import aprslib
@ -9,7 +7,7 @@ import aprslib
LOG = logging.getLogger("APRSD")
class Client(object):
class Client:
"""Singleton client class that constructs the aprslib connection."""
_instance = None
@ -19,7 +17,7 @@ class Client(object):
def __new__(cls, *args, **kwargs):
"""This magic turns this into a singleton."""
if cls._instance is None:
cls._instance = super(Client, cls).__new__(cls)
cls._instance = super().__new__(cls)
# Put any initialization here.
return cls._instance
@ -82,7 +80,7 @@ class Aprsdis(aprslib.IS):
"""
try:
self.sock.setblocking(0)
except socket.error as e:
except OSError as e:
self.logger.error("socket error when setblocking(0): %s" % str(e))
raise aprslib.ConnectionDrop("connection dropped")
@ -93,7 +91,10 @@ class Aprsdis(aprslib.IS):
# set a select timeout, so we get a chance to exit
# when user hits CTRL-C
readable, writable, exceptional = select.select(
[self.sock], [], [], self.select_timeout
[self.sock],
[],
[],
self.select_timeout,
)
if not readable:
continue
@ -105,7 +106,7 @@ class Aprsdis(aprslib.IS):
if not short_buf:
self.logger.error("socket.recv(): returned empty")
raise aprslib.ConnectionDrop("connection dropped")
except socket.error as e:
except OSError as e:
# self.logger.error("socket error on recv(): %s" % str(e))
if "Resource temporarily unavailable" in str(e):
if not blocking:

View File

@ -1,18 +1,15 @@
# -*- coding: utf-8 -*-
import datetime
import email
from email.mime.text import MIMEText
import imaplib
import logging
import re
import smtplib
import time
from email.mime.text import MIMEText
import imapclient
import six
from validate_email import validate_email
from aprsd import messaging, threads
import imapclient
from validate_email import validate_email
LOG = logging.getLogger("APRSD")
@ -30,7 +27,10 @@ def _imap_connect():
try:
server = imapclient.IMAPClient(
CONFIG["imap"]["host"], port=imap_port, use_uid=True, ssl=use_ssl
CONFIG["imap"]["host"],
port=imap_port,
use_uid=True,
ssl=use_ssl,
)
except Exception:
LOG.error("Failed to connect IMAP server")
@ -53,7 +53,7 @@ def _smtp_connect():
use_ssl = CONFIG["smtp"].get("use_ssl", False)
msg = "{}{}:{}".format("SSL " if use_ssl else "", host, smtp_port)
LOG.debug(
"Connect to SMTP host {} with user '{}'".format(msg, CONFIG["imap"]["login"])
"Connect to SMTP host {} with user '{}'".format(msg, CONFIG["imap"]["login"]),
)
try:
@ -84,7 +84,7 @@ def validate_shortcuts(config):
LOG.info(
"Validating {} Email shortcuts. This can take up to 10 seconds"
" per shortcut".format(len(shortcuts))
" per shortcut".format(len(shortcuts)),
)
delete_keys = []
for key in shortcuts:
@ -102,8 +102,8 @@ def validate_shortcuts(config):
if not is_valid:
LOG.error(
"'{}' is an invalid email address. Removing shortcut".format(
shortcuts[key]
)
shortcuts[key],
),
)
delete_keys.append(key)
@ -173,14 +173,18 @@ def parse_email(msgid, data, server):
if part.get_content_type() == "text/plain":
LOG.debug("Email got text/plain")
text = six.text_type(
part.get_payload(decode=True), str(charset), "ignore"
text = str(
part.get_payload(decode=True),
str(charset),
"ignore",
).encode("utf8", "replace")
if part.get_content_type() == "text/html":
LOG.debug("Email got text/html")
html = six.text_type(
part.get_payload(decode=True), str(charset), "ignore"
html = str(
part.get_payload(decode=True),
str(charset),
"ignore",
).encode("utf8", "replace")
if text is not None:
@ -192,12 +196,15 @@ def parse_email(msgid, data, server):
# email.uscc.net sends no charset, blows up unicode function below
LOG.debug("Email is not multipart")
if msg.get_content_charset() is None:
text = six.text_type(
msg.get_payload(decode=True), "US-ASCII", "ignore"
).encode("utf8", "replace")
text = str(msg.get_payload(decode=True), "US-ASCII", "ignore").encode(
"utf8",
"replace",
)
else:
text = six.text_type(
msg.get_payload(decode=True), msg.get_content_charset(), "ignore"
text = str(
msg.get_payload(decode=True),
msg.get_content_charset(),
"ignore",
).encode("utf8", "replace")
body = text.strip()
@ -266,11 +273,11 @@ def resend_email(count, fromcall):
month = date.strftime("%B")[:3] # Nov, Mar, Apr
day = date.day
year = date.year
today = "%s-%s-%s" % (day, month, year)
today = "{}-{}-{}".format(day, month, year)
shortcuts = CONFIG["shortcuts"]
# swap key/value
shortcuts_inverted = dict([[v, k] for k, v in shortcuts.items()])
shortcuts_inverted = {v: k for k, v in shortcuts.items()}
try:
server = _imap_connect()
@ -310,7 +317,7 @@ def resend_email(count, fromcall):
# thinking this is a duplicate message.
# The FT1XDR pretty much ignores the aprs message number in this
# regard. The FTM400 gets it right.
reply = "No new msg %s:%s:%s" % (
reply = "No new msg {}:{}:{}".format(
str(h).zfill(2),
str(m).zfill(2),
str(s).zfill(2),
@ -328,7 +335,7 @@ def resend_email(count, fromcall):
class APRSDEmailThread(threads.APRSDThread):
def __init__(self, msg_queues, config):
super(APRSDEmailThread, self).__init__("EmailThread")
super().__init__("EmailThread")
self.msg_queues = msg_queues
self.config = config
@ -354,13 +361,13 @@ class APRSDEmailThread(threads.APRSDThread):
shortcuts = CONFIG["shortcuts"]
# swap key/value
shortcuts_inverted = dict([[v, k] for k, v in shortcuts.items()])
shortcuts_inverted = {v: k for k, v in shortcuts.items()}
date = datetime.datetime.now()
month = date.strftime("%B")[:3] # Nov, Mar, Apr
day = date.day
year = date.year
today = "%s-%s-%s" % (day, month, year)
today = "{}-{}-{}".format(day, month, year)
server = None
try:
@ -378,7 +385,8 @@ class APRSDEmailThread(threads.APRSDThread):
envelope = data[b"ENVELOPE"]
# LOG.debug('ID:%d "%s" (%s)' % (msgid, envelope.subject.decode(), envelope.date))
f = re.search(
r"'([[A-a][0-9]_-]+@[[A-a][0-9]_-\.]+)", str(envelope.from_[0])
r"'([[A-a][0-9]_-]+@[[A-a][0-9]_-\.]+)",
str(envelope.from_[0]),
)
if f is not None:
from_addr = f.group(1)

View File

@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
import argparse
import logging
from logging.handlers import RotatingFileHandler
import socketserver
import sys
import time
from logging.handlers import RotatingFileHandler
from aprsd import utils
@ -74,7 +73,7 @@ def main():
ip = CONFIG["aprs"]["host"]
port = CONFIG["aprs"]["port"]
LOG.info("Start server listening on %s:%s" % (args.ip, args.port))
LOG.info("Start server listening on {}:{}".format(args.ip, args.port))
with socketserver.TCPServer((ip, port), MyAPRSTCPHandler) as server:
server.serve_forever()

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# @author Sinu John
# sinuvian at gmail dot com

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Listen on amateur radio aprs-is network for messages and respond to them.
# You must have an amateur radio callsign to use this software. You must
@ -22,23 +21,22 @@
# python included libs
import logging
from logging import NullHandler
from logging.handlers import RotatingFileHandler
import os
import queue
import signal
import sys
import threading
import time
from logging import NullHandler
from logging.handlers import RotatingFileHandler
import aprslib
import click
import click_completion
import yaml
# local imports here
import aprsd
from aprsd import client, email, messaging, plugin, threads, utils
import aprslib
import click
import click_completion
import yaml
# setup the global logger
# logging.basicConfig(level=logging.DEBUG) # level=10
@ -99,7 +97,9 @@ def main():
@main.command()
@click.option(
"-i", "--case-insensitive/--no-case-insensitive", help="Case insensitive completion"
"-i",
"--case-insensitive/--no-case-insensitive",
help="Case insensitive completion",
)
@click.argument(
"shell",
@ -118,10 +118,14 @@ def show(shell, case_insensitive):
@main.command()
@click.option(
"--append/--overwrite", help="Append the completion code to the file", default=None
"--append/--overwrite",
help="Append the completion code to the file",
default=None,
)
@click.option(
"-i", "--case-insensitive/--no-case-insensitive", help="Case insensitive completion"
"-i",
"--case-insensitive/--no-case-insensitive",
help="Case insensitive completion",
)
@click.argument(
"shell",
@ -137,16 +141,19 @@ def install(append, case_insensitive, shell, path):
else {}
)
shell, path = click_completion.core.install(
shell=shell, path=path, append=append, extra_env=extra_env
shell=shell,
path=path,
append=append,
extra_env=extra_env,
)
click.echo("%s completion installed in %s" % (shell, path))
click.echo("{} completion installed in {}".format(shell, path))
def signal_handler(signal, frame):
global server_vent
LOG.info(
"Ctrl+C, Sending all threads exit! Can take up to 10 seconds to exit all threads"
"Ctrl+C, Sending all threads exit! Can take up to 10 seconds to exit all threads",
)
threads.APRSDThreadList().stop_all()
server_event.set()
@ -191,7 +198,8 @@ def sample_config():
default="DEBUG",
show_default=True,
type=click.Choice(
["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], case_sensitive=False
["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
case_sensitive=False,
),
show_choices=True,
help="The log level to use for aprsd.log",
@ -220,7 +228,13 @@ def sample_config():
@click.argument("tocallsign")
@click.argument("command", nargs=-1)
def send_message(
loglevel, quiet, config_file, aprs_login, aprs_password, tocallsign, command
loglevel,
quiet,
config_file,
aprs_login,
aprs_password,
tocallsign,
command,
):
"""Send a message to a callsign via APRS_IS."""
global got_ack, got_response
@ -273,7 +287,9 @@ def send_message(
got_response = True
# Send the ack back?
ack = messaging.AckMessage(
config["aprs"]["login"], fromcall, msg_id=msg_number
config["aprs"]["login"],
fromcall,
msg_id=msg_number,
)
ack.send_direct()
@ -312,7 +328,8 @@ def send_message(
default="DEBUG",
show_default=True,
type=click.Choice(
["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], case_sensitive=False
["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
case_sensitive=False,
),
show_choices=True,
help="The log level to use for aprsd.log",

View File

@ -1,14 +1,13 @@
# -*- coding: utf-8 -*-
import abc
import datetime
import logging
from multiprocessing import RawValue
import os
import pathlib
import pickle
import re
import threading
import time
from multiprocessing import RawValue
from aprsd import client, threads, utils
@ -19,7 +18,7 @@ LOG = logging.getLogger("APRSD")
NULL_MESSAGE = -1
class MsgTrack(object):
class MsgTrack:
"""Class to keep track of outstanding text messages.
This is a thread safe class that keeps track of active
@ -47,7 +46,7 @@ class MsgTrack(object):
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(MsgTrack, cls).__new__(cls)
cls._instance = super().__new__(cls)
cls._instance.track = {}
cls._instance.lock = threading.Lock()
return cls._instance
@ -129,7 +128,7 @@ class MsgTrack(object):
self.track = {}
class MessageCounter(object):
class MessageCounter:
"""
Global message id counter class.
@ -147,7 +146,7 @@ class MessageCounter(object):
def __new__(cls, *args, **kwargs):
"""Make this a singleton class."""
if cls._instance is None:
cls._instance = super(MessageCounter, cls).__new__(cls)
cls._instance = super().__new__(cls)
cls._instance.val = RawValue("i", 1)
cls._instance.lock = threading.Lock()
return cls._instance
@ -173,7 +172,7 @@ class MessageCounter(object):
return str(self.val.value)
class Message(object, metaclass=abc.ABCMeta):
class Message(metaclass=abc.ABCMeta):
"""Base Message Class."""
# The message id to send over the air
@ -204,7 +203,7 @@ class TextMessage(Message):
message = None
def __init__(self, fromcall, tocall, message, msg_id=None, allow_delay=True):
super(TextMessage, self).__init__(fromcall, tocall, msg_id)
super().__init__(fromcall, tocall, msg_id)
self.message = message
# do we try and save this message for later if we don't get
# an ack? Some messages we don't want to do this ever.
@ -213,7 +212,10 @@ class TextMessage(Message):
def __repr__(self):
"""Build raw string to send over the air."""
return "{}>APRS::{}:{}{{{}\n".format(
self.fromcall, self.tocall.ljust(9), self._filter_for_send(), str(self.id)
self.fromcall,
self.tocall.ljust(9),
self._filter_for_send(),
str(self.id),
)
def __str__(self):
@ -222,7 +224,11 @@ class TextMessage(Message):
now = datetime.datetime.now()
delta = now - self.last_send_time
return "{}>{} Msg({})({}): '{}'".format(
self.fromcall, self.tocall, self.id, delta, self.message
self.fromcall,
self.tocall,
self.id,
delta,
self.message,
)
def _filter_for_send(self):
@ -259,9 +265,7 @@ class SendMessageThread(threads.APRSDThread):
def __init__(self, message):
self.msg = message
name = self.msg.message[:5]
super(SendMessageThread, self).__init__(
"SendMessage-{}-{}".format(self.msg.id, name)
)
super().__init__("SendMessage-{}-{}".format(self.msg.id, name))
def loop(self):
"""Loop until a message is acked or it gets delayed.
@ -326,11 +330,13 @@ class AckMessage(Message):
"""Class for building Acks and sending them."""
def __init__(self, fromcall, tocall, msg_id):
super(AckMessage, self).__init__(fromcall, tocall, msg_id=msg_id)
super().__init__(fromcall, tocall, msg_id=msg_id)
def __repr__(self):
return "{}>APRS::{}:ack{}\n".format(
self.fromcall, self.tocall.ljust(9), self.id
self.fromcall,
self.tocall.ljust(9),
self.id,
)
def __str__(self):
@ -378,7 +384,7 @@ class AckMessage(Message):
class SendAckThread(threads.APRSDThread):
def __init__(self, ack):
self.ack = ack
super(SendAckThread, self).__init__("SendAck-{}".format(self.ack.id))
super().__init__("SendAck-{}".format(self.ack.id))
def loop(self):
"""Separate thread to send acks with retries."""

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# The base plugin class
import abc
import fnmatch
@ -12,14 +11,12 @@ import shutil
import subprocess
import time
import pluggy
import requests
import six
from thesmuggler import smuggle
import aprsd
from aprsd import email, messaging
from aprsd.fuzzyclock import fuzzy
import pluggy
import requests
from thesmuggler import smuggle
# setup the global logger
LOG = logging.getLogger("APRSD")
@ -39,7 +36,7 @@ CORE_PLUGINS = [
]
class PluginManager(object):
class PluginManager:
# The singleton instance object for this class
_instance = None
@ -52,7 +49,7 @@ class PluginManager(object):
def __new__(cls, *args, **kwargs):
"""This magic turns this into a singleton."""
if cls._instance is None:
cls._instance = super(PluginManager, cls).__new__(cls)
cls._instance = super().__new__(cls)
# Put any initialization here.
return cls._instance
@ -79,7 +76,7 @@ class PluginManager(object):
for mem_name, obj in inspect.getmembers(module):
if inspect.isclass(obj) and self.is_plugin(obj):
self.obj_list.append(
{"name": mem_name, "obj": obj(self.config)}
{"name": mem_name, "obj": obj(self.config)},
)
return self.obj_list
@ -108,14 +105,16 @@ class PluginManager(object):
return
assert hasattr(module, class_name), "class {} is not in {}".format(
class_name, module_name
class_name,
module_name,
)
# click.echo('reading class {} from module {}'.format(
# class_name, module_name))
cls = getattr(module, class_name)
if super_cls is not None:
assert issubclass(cls, super_cls), "class {} should inherit from {}".format(
class_name, super_cls.__name__
class_name,
super_cls.__name__,
)
# click.echo('initialising {} with params {}'.format(class_name, kwargs))
obj = cls(**kwargs)
@ -131,13 +130,17 @@ class PluginManager(object):
plugin_obj = None
try:
plugin_obj = self._create_class(
plugin_name, APRSDPluginBase, config=self.config
plugin_name,
APRSDPluginBase,
config=self.config,
)
if plugin_obj:
LOG.info(
"Registering Command plugin '{}'({}) '{}'".format(
plugin_name, plugin_obj.version, plugin_obj.command_regex
)
plugin_name,
plugin_obj.version,
plugin_obj.command_regex,
),
)
self._pluggy_pm.register(plugin_obj)
except Exception as ex:
@ -173,8 +176,10 @@ class PluginManager(object):
if plugin_obj:
LOG.info(
"Registering Command plugin '{}'({}) '{}'".format(
o["name"], o["obj"].version, o["obj"].command_regex
)
o["name"],
o["obj"].version,
o["obj"].command_regex,
),
)
self._pluggy_pm.register(o["obj"])
@ -203,8 +208,7 @@ class APRSDCommandSpec:
pass
@six.add_metaclass(abc.ABCMeta)
class APRSDPluginBase(object):
class APRSDPluginBase(metaclass=abc.ABCMeta):
def __init__(self, config):
"""The aprsd config object is stored."""
self.config = config
@ -257,7 +261,8 @@ class FortunePlugin(APRSDPluginBase):
try:
process = subprocess.Popen(
[fortune_path, "-s", "-n 60"], stdout=subprocess.PIPE
[fortune_path, "-s", "-n 60"],
stdout=subprocess.PIPE,
)
reply = process.communicate()[0]
reply = reply.decode(errors="ignore").rstrip()
@ -406,7 +411,10 @@ class TimePlugin(APRSDPluginBase):
m = stm.tm_min
cur_time = fuzzy(h, m, 1)
reply = "{} ({}:{} PDT) ({})".format(
cur_time, str(h), str(m).rjust(2, "0"), message.rstrip()
cur_time,
str(h),
str(m).rjust(2, "0"),
message.rstrip(),
)
return reply
@ -497,7 +505,7 @@ class EmailPlugin(APRSDPluginBase):
# send recipient link to aprs.fi map
if content == "mapme":
content = "Click for my location: http://aprs.fi/{}".format(
self.config["ham"]["callsign"]
self.config["ham"]["callsign"],
)
too_soon = 0
now = time.time()
@ -521,7 +529,7 @@ class EmailPlugin(APRSDPluginBase):
LOG.debug(
"DEBUG: email_sent_dict is big ("
+ str(len(self.email_sent_dict))
+ ") clearing out."
+ ") clearing out.",
)
self.email_sent_dict.clear()
self.email_sent_dict[ack] = now
@ -529,7 +537,7 @@ class EmailPlugin(APRSDPluginBase):
LOG.info(
"Email for message number "
+ ack
+ " recently sent, not sending again."
+ " recently sent, not sending again.",
)
else:
reply = "Bad email address"

View File

@ -1,13 +1,11 @@
# -*- coding: utf-8 -*-
import abc
import logging
import queue
import threading
import time
import aprslib
from aprsd import client, messaging, plugin
import aprslib
LOG = logging.getLogger("APRSD")
@ -16,7 +14,7 @@ TX_THREAD = "TX"
EMAIL_THREAD = "Email"
class APRSDThreadList(object):
class APRSDThreadList:
"""Singleton class that keeps track of application wide threads."""
_instance = None
@ -26,7 +24,7 @@ class APRSDThreadList(object):
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(APRSDThreadList, cls).__new__(cls)
cls._instance = super().__new__(cls)
cls.lock = threading.Lock()
cls.threads_list = []
return cls._instance
@ -48,7 +46,7 @@ class APRSDThreadList(object):
class APRSDThread(threading.Thread, metaclass=abc.ABCMeta):
def __init__(self, name):
super(APRSDThread, self).__init__(name=name)
super().__init__(name=name)
self.thread_stop = False
APRSDThreadList().add(self)
@ -67,7 +65,7 @@ class APRSDThread(threading.Thread, metaclass=abc.ABCMeta):
class APRSDRXThread(APRSDThread):
def __init__(self, msg_queues, config):
super(APRSDRXThread, self).__init__("RX_MSG")
super().__init__("RX_MSG")
self.msg_queues = msg_queues
self.config = config
@ -112,7 +110,11 @@ class APRSDRXThread(APRSDThread):
ack_num = packet.get("msgNo")
LOG.info("Got ack for message {}".format(ack_num))
messaging.log_message(
"ACK", packet["raw"], None, ack=ack_num, fromcall=packet["from"]
"ACK",
packet["raw"],
None,
ack=ack_num,
fromcall=packet["from"],
)
tracker = messaging.MsgTrack()
tracker.remove(ack_num)
@ -153,7 +155,9 @@ class APRSDRXThread(APRSDThread):
LOG.debug("Sending '{}'".format(reply))
msg = messaging.TextMessage(
self.config["aprs"]["login"], fromcall, reply
self.config["aprs"]["login"],
fromcall,
reply,
)
self.msg_queues["tx"].put(msg)
else:
@ -166,7 +170,9 @@ class APRSDRXThread(APRSDThread):
reply = "Usage: {}".format(", ".join(names))
msg = messaging.TextMessage(
self.config["aprs"]["login"], fromcall, reply
self.config["aprs"]["login"],
fromcall,
reply,
)
self.msg_queues["tx"].put(msg)
except Exception as ex:
@ -178,7 +184,9 @@ class APRSDRXThread(APRSDThread):
# let any threads do their thing, then ack
# send an ack last
ack = messaging.AckMessage(
self.config["aprs"]["login"], fromcall, msg_id=msg_id
self.config["aprs"]["login"],
fromcall,
msg_id=msg_id,
)
self.msg_queues["tx"].put(ack)
LOG.debug("Packet processing complete")
@ -213,7 +221,7 @@ class APRSDRXThread(APRSDThread):
class APRSDTXThread(APRSDThread):
def __init__(self, msg_queues, config):
super(APRSDTXThread, self).__init__("TX_MSG")
super().__init__("TX_MSG")
self.msg_queues = msg_queues
self.config = config

View File

@ -1,17 +1,15 @@
# -*- coding: utf-8 -*-
"""Utilities and helper functions."""
import errno
import functools
import os
from pathlib import Path
import sys
import threading
from pathlib import Path
import click
import yaml
from aprsd import plugin
import click
import yaml
# an example of what should be in the ~/.aprsd/config.yml
DEFAULT_CONFIG_DICT = {
@ -103,13 +101,13 @@ def get_config(config_file):
"""This tries to read the yaml config from <config_file>."""
config_file_expanded = os.path.expanduser(config_file)
if os.path.exists(config_file_expanded):
with open(config_file_expanded, "r") as stream:
with open(config_file_expanded) as stream:
config = yaml.load(stream, Loader=yaml.FullLoader)
return config
else:
if config_file == DEFAULT_CONFIG_FILE:
click.echo(
"{} is missing, creating config file".format(config_file_expanded)
"{} is missing, creating config file".format(config_file_expanded),
)
create_default_config()
msg = (
@ -144,7 +142,10 @@ def parse_config(config_file):
if name and name not in config[section]:
if not default:
fail(
"'%s' was not in '%s' section of config file" % (name, section)
"'{}' was not in '{}' section of config file".format(
name,
section,
),
)
else:
config[section][name] = default
@ -166,7 +167,10 @@ def parse_config(config_file):
# special check here to make sure user has edited the config file
# and changed the ham callsign
check_option(
config, "ham", "callsign", default_fail=DEFAULT_CONFIG_DICT["ham"]["callsign"]
config,
"ham",
"callsign",
default_fail=DEFAULT_CONFIG_DICT["ham"]["callsign"],
)
check_option(config, "aprs", "login")
check_option(config, "aprs", "password")

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
import logging
from aprsd import plugin

36
pyproject.toml Normal file
View File

@ -0,0 +1,36 @@
[build-system]
requires = ["setuptools>=46.0", "wheel"]
build-backend = "setuptools.build_meta"
[tool.black]
# Use the more relaxed max line length permitted in PEP8.
line-length = 88
target-version = ["py36", "py37", "py38"]
# black will automatically exclude all files listed in .gitignore
include = '\.pyi?$'
exclude = '''
/(
\.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
)/
'''
[tool.isort]
profile = "black"
line_length = 88
force_sort_within_sections = true
# Inform isort of paths to import names that should be considered part of the "First Party" group.
src_paths = ["src/openstack_loadtest"]
skip_gitignore = true
# If you need to skip/exclude folders, consider using skip_glob as that will allow the
# isort defaults for skip to remain without the need to duplicate them.
[tool.coverage.run]
branch = true

View File

@ -1,15 +1,16 @@
[metadata]
name = aprsd
summary = Amateur radio APRS daemon which listens for messages and responds
description-file =
README.rst
long-description-content-type = text/x-rst; charset=UTF-8
long_description = file: README.rst
long_description_content_type = text/x-rst
author = Craig Lamparter
author-email = something@somewhere.com
author_email = something@somewhere.com
classifier =
Topic :: Communications :: Ham Radio
Operating System :: POSIX :: Linux
Programming Language :: Python
description_file =
README.rst
summary = Amateur radio APRS daemon which listens for messages and responds
[global]
setup-hooks =

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
import sys
import unittest
@ -7,7 +6,7 @@ from aprsd import email
if sys.version_info >= (3, 2):
from unittest import mock
else:
import mock
from unittest import mock
class TestMain(unittest.TestCase):

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
import unittest
from unittest import mock
@ -57,7 +56,10 @@ class TestPlugin(unittest.TestCase):
message = "time"
expected = "{} ({}:{} PDT) ({})".format(
cur_time, str(h), str(m).rjust(2, "0"), message.rstrip()
cur_time,
str(h),
str(m).rjust(2, "0"),
message.rstrip(),
)
actual = time_plugin.run(fromcall, message, ack)
self.assertEqual(expected, actual)