diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 42761b3..f73a842 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,31 +17,7 @@ repos: hooks: - id: setup-cfg-fmt -- repo: https://github.com/asottile/add-trailing-comma - rev: v2.0.2 +- repo: https://github.com/dizballanze/gray + rev: v0.10.1 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] + - id: gray diff --git a/aprsd/__init__.py b/aprsd/__init__.py index 221b6c8..9f55804 100644 --- a/aprsd/__init__.py +++ b/aprsd/__init__.py @@ -12,4 +12,5 @@ import pbr.version + __version__ = pbr.version.VersionInfo("aprsd").version_string() diff --git a/aprsd/client.py b/aprsd/client.py index 1a523c0..87faf5b 100644 --- a/aprsd/client.py +++ b/aprsd/client.py @@ -2,19 +2,17 @@ import logging import select import time -import aprsd -from aprsd import stats import aprslib from aprslib import is_py3 from aprslib.exceptions import ( - ConnectionDrop, - ConnectionError, - GenericError, - LoginError, - ParseError, + ConnectionDrop, ConnectionError, GenericError, LoginError, ParseError, UnknownFormat, ) +import aprsd +from aprsd import stats + + LOG = logging.getLogger("APRSD") @@ -67,15 +65,15 @@ class Client: connected = True backoff = 1 except LoginError as e: - LOG.error("Failed to login to APRS-IS Server '{}'".format(e)) + LOG.error(f"Failed to login to APRS-IS Server '{e}'") connected = False raise e except Exception as e: - LOG.error("Unable to connect to APRS-IS server. '{}' ".format(e)) + LOG.error(f"Unable to connect to APRS-IS server. '{e}' ") time.sleep(backoff) backoff = backoff * 2 continue - LOG.debug("Logging in to APRS-IS with user '%s'" % user) + LOG.debug(f"Logging in to APRS-IS with user '{user}'") return aprs_client @@ -99,7 +97,7 @@ class Aprsdis(aprslib.IS): try: self.sock.setblocking(0) except OSError as e: - self.logger.error("socket error when setblocking(0): %s" % str(e)) + self.logger.error(f"socket error when setblocking(0): {str(e)}") raise aprslib.ConnectionDrop("connection dropped") while not self.thread_stop: @@ -169,14 +167,14 @@ class Aprsdis(aprslib.IS): else: server_string = e.replace("server ", "") - self.logger.info("Connected to {}".format(server_string)) + self.logger.info(f"Connected to {server_string}") self.server_string = server_string stats.APRSDStats().set_aprsis_server(server_string) if callsign == "": raise LoginError("Server responded with empty callsign???") if callsign != self.callsign: - raise LoginError("Server: %s" % test) + raise LoginError(f"Server: {test}") if status != "verified," and self.passwd != "-1": raise LoginError("Password is incorrect") @@ -191,7 +189,7 @@ class Aprsdis(aprslib.IS): raise except Exception as e: self.close() - self.logger.error("Failed to login '{}'".format(e)) + self.logger.error(f"Failed to login '{e}'") raise LoginError("Failed to login") def consumer(self, callback, blocking=True, immortal=False, raw=False): diff --git a/aprsd/dev.py b/aprsd/dev.py index a53ab01..a8052dd 100644 --- a/aprsd/dev.py +++ b/aprsd/dev.py @@ -9,11 +9,13 @@ from logging.handlers import RotatingFileHandler import os import sys +import click +import click_completion + # local imports here import aprsd from aprsd import client, email, plugin, utils -import click -import click_completion + # setup the global logger # logging.basicConfig(level=logging.DEBUG) # level=10 @@ -48,7 +50,7 @@ Available shell types: %s Default type: auto """ % "\n ".join( - "{:<12} {}".format(k, click_completion.core.shells[k]) + f"{k:<12} {click_completion.core.shells[k]}" for k in sorted(click_completion.core.shells.keys()) ) @@ -110,7 +112,7 @@ def install(append, case_insensitive, shell, path): append=append, extra_env=extra_env, ) - click.echo("{} completion installed in {}".format(shell, path)) + click.echo(f"{shell} completion installed in {path}") # Setup the logging faciility @@ -180,10 +182,10 @@ def test_plugin( email.CONFIG = config setup_logging(config, loglevel, False) - LOG.info("Test APRSD PLugin version: {}".format(aprsd.__version__)) + LOG.info(f"Test APRSD PLugin version: {aprsd.__version__}") if type(message) is tuple: message = " ".join(message) - LOG.info("P'{}' F'{}' C'{}'".format(plugin_path, fromcall, message)) + LOG.info(f"P'{plugin_path}' F'{fromcall}' C'{message}'") client.Client(config) pm = plugin.PluginManager(config) @@ -192,7 +194,7 @@ def test_plugin( packet = {"from": fromcall, "message_text": message, "msgNo": 1} reply = obj.run(packet) - LOG.info("Result = '{}'".format(reply)) + LOG.info(f"Result = '{reply}'") if __name__ == "__main__": diff --git a/aprsd/email.py b/aprsd/email.py index 12d3840..039e204 100644 --- a/aprsd/email.py +++ b/aprsd/email.py @@ -7,10 +7,12 @@ import re import smtplib import time -from aprsd import messaging, stats, threads, trace import imapclient from validate_email import validate_email +from aprsd import messaging, stats, threads, trace + + LOG = logging.getLogger("APRSD") # This gets forced set from main.py prior to being used internally @@ -45,7 +47,7 @@ def _imap_connect(): ) except (imaplib.IMAP4.error, Exception) as e: msg = getattr(e, "message", repr(e)) - LOG.error("Failed to login {}".format(msg)) + LOG.error(f"Failed to login {msg}") return server.select_folder("INBOX") @@ -87,7 +89,7 @@ def _smtp_connect(): LOG.error("Couldn't connect to SMTP Server") return - LOG.debug("Connected to smtp host {}".format(msg)) + LOG.debug(f"Connected to smtp host {msg}") debug = CONFIG["aprsd"]["email"]["smtp"].get("debug", False) if debug: @@ -103,7 +105,7 @@ def _smtp_connect(): LOG.error("Couldn't connect to SMTP Server") return - LOG.debug("Logged into SMTP server {}".format(msg)) + LOG.debug(f"Logged into SMTP server {msg}") return server @@ -118,7 +120,7 @@ def validate_shortcuts(config): ) delete_keys = [] for key in shortcuts: - LOG.info("Validating {}:{}".format(key, shortcuts[key])) + LOG.info(f"Validating {key}:{shortcuts[key]}") is_valid = validate_email( email_address=shortcuts[key], check_regex=True, @@ -183,7 +185,7 @@ def parse_email(msgid, data, server): from_addr = f.group(1) else: from_addr = "noaddr" - LOG.debug("Got a message from '{}'".format(from_addr)) + LOG.debug(f"Got a message from '{from_addr}'") try: m = server.fetch([msgid], ["RFC822"]) except Exception as e: @@ -317,7 +319,7 @@ def resend_email(count, fromcall): month = date.strftime("%B")[:3] # Nov, Mar, Apr day = date.day year = date.year - today = "{}-{}-{}".format(day, month, year) + today = f"{day}-{month}-{year}" shortcuts = CONFIG["aprsd"]["email"]["shortcuts"] # swap key/value @@ -434,7 +436,7 @@ class APRSDEmailThread(threads.APRSDThread): month = date.strftime("%B")[:3] # Nov, Mar, Apr day = date.day year = date.year - today = "{}-{}-{}".format(day, month, year) + today = f"{day}-{month}-{year}" server = None try: @@ -450,7 +452,7 @@ class APRSDEmailThread(threads.APRSDThread): except Exception as e: LOG.exception("IMAP failed to search for messages since today.", e) continue - LOG.debug("{} messages received today".format(len(messages))) + LOG.debug(f"{len(messages)} messages received today") try: _msgs = server.fetch(messages, ["ENVELOPE"]) diff --git a/aprsd/fake_aprs.py b/aprsd/fake_aprs.py index f6ed353..8eafe6b 100644 --- a/aprsd/fake_aprs.py +++ b/aprsd/fake_aprs.py @@ -7,6 +7,7 @@ import time from aprsd import utils + # command line args parser = argparse.ArgumentParser() parser.add_argument( @@ -56,7 +57,7 @@ class MyAPRSTCPHandler(socketserver.BaseRequestHandler): def handle(self): # self.request is the TCP socket connected to the client self.data = self.request.recv(1024).strip() - LOG.debug("{} wrote:".format(self.client_address[0])) + LOG.debug(f"{self.client_address[0]} wrote:") LOG.debug(self.data) # just send back the same data, but upper-cased self.request.sendall(self.data.upper()) @@ -73,7 +74,7 @@ def main(): ip = CONFIG["aprs"]["host"] port = CONFIG["aprs"]["port"] - LOG.info("Start server listening on {}:{}".format(args.ip, args.port)) + LOG.info(f"Start server listening on {args.ip}:{args.port}") with socketserver.TCPServer((ip, port), MyAPRSTCPHandler) as server: server.serve_forever() diff --git a/aprsd/flask.py b/aprsd/flask.py index f148134..7577425 100644 --- a/aprsd/flask.py +++ b/aprsd/flask.py @@ -5,13 +5,15 @@ from logging import NullHandler from logging.handlers import RotatingFileHandler import sys -import aprsd -from aprsd import messaging, packets, plugin, stats, utils import flask import flask_classful from flask_httpauth import HTTPBasicAuth from werkzeug.security import check_password_hash, generate_password_hash +import aprsd +from aprsd import messaging, packets, plugin, stats, utils + + LOG = logging.getLogger("APRSD") auth = HTTPBasicAuth() diff --git a/aprsd/healthcheck.py b/aprsd/healthcheck.py index 35e3a6e..4e4b212 100644 --- a/aprsd/healthcheck.py +++ b/aprsd/healthcheck.py @@ -13,13 +13,15 @@ import os import re import sys -# local imports here -import aprsd -from aprsd import utils import click import click_completion import requests +# local imports here +import aprsd +from aprsd import utils + + # setup the global logger # logging.basicConfig(level=logging.DEBUG) # level=10 LOG = logging.getLogger("APRSD") @@ -53,7 +55,7 @@ Available shell types: %s Default type: auto """ % "\n ".join( - "{:<12} {}".format(k, click_completion.core.shells[k]) + f"{k:<12} {click_completion.core.shells[k]}" for k in sorted(click_completion.core.shells.keys()) ) @@ -115,7 +117,7 @@ def install(append, case_insensitive, shell, path): append=append, extra_env=extra_env, ) - click.echo("{} completion installed in {}".format(shell, path)) + click.echo(f"{shell} completion installed in {path}") # Setup the logging faciility @@ -192,14 +194,14 @@ def check(loglevel, config_file, health_url, timeout): config = utils.parse_config(config_file) setup_logging(config, loglevel, False) - LOG.debug("APRSD HealthCheck version: {}".format(aprsd.__version__)) + LOG.debug(f"APRSD HealthCheck version: {aprsd.__version__}") try: url = health_url response = requests.get(url, timeout=timeout) response.raise_for_status() except Exception as ex: - LOG.error("Failed to fetch healthcheck url '{}' : '{}'".format(url, ex)) + LOG.error(f"Failed to fetch healthcheck url '{url}' : '{ex}'") sys.exit(-1) else: stats = json.loads(response.text) @@ -212,7 +214,7 @@ def check(loglevel, config_file, health_url, timeout): max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 0} max_delta = datetime.timedelta(**max_timeout) if d > max_delta: - LOG.error("Email thread is very old! {}".format(d)) + LOG.error(f"Email thread is very old! {d}") sys.exit(-1) aprsis_last_update = stats["stats"]["aprs-is"]["last_update"] @@ -221,7 +223,7 @@ def check(loglevel, config_file, health_url, timeout): max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 0} max_delta = datetime.timedelta(**max_timeout) if d > max_delta: - LOG.error("APRS-IS last update is very old! {}".format(d)) + LOG.error(f"APRS-IS last update is very old! {d}") sys.exit(-1) sys.exit(0) diff --git a/aprsd/listen.py b/aprsd/listen.py index 9d0ced7..8d8a9c0 100644 --- a/aprsd/listen.py +++ b/aprsd/listen.py @@ -29,14 +29,16 @@ import signal import sys import time -# local imports here -import aprsd -from aprsd import client, messaging, stats, threads, trace, utils import aprslib from aprslib.exceptions import LoginError import click import click_completion +# local imports here +import aprsd +from aprsd import client, messaging, stats, threads, trace, utils + + # setup the global logger # logging.basicConfig(level=logging.DEBUG) # level=10 LOG = logging.getLogger("APRSD") @@ -78,7 +80,7 @@ Available shell types: %s Default type: auto """ % "\n ".join( - "{:<12} {}".format(k, click_completion.core.shells[k]) + f"{k:<12} {click_completion.core.shells[k]}" for k in sorted(click_completion.core.shells.keys()) ) @@ -140,7 +142,7 @@ def install(append, case_insensitive, shell, path): append=append, extra_env=extra_env, ) - click.echo("{} completion installed in {}".format(shell, path)) + click.echo(f"{shell} completion installed in {path}") def signal_handler(sig, frame): @@ -270,22 +272,22 @@ def listen( messaging.CONFIG = config setup_logging(config, loglevel, quiet) - LOG.info("APRSD TEST Started version: {}".format(aprsd.__version__)) + LOG.info(f"APRSD TEST Started version: {aprsd.__version__}") if type(command) is tuple: command = " ".join(command) if not quiet: if raw: - LOG.info("L'{}' R'{}'".format(aprs_login, raw)) + LOG.info(f"L'{aprs_login}' R'{raw}'") else: - LOG.info("L'{}' To'{}' C'{}'".format(aprs_login, tocallsign, command)) + LOG.info(f"L'{aprs_login}' To'{tocallsign}' C'{command}'") flat_config = utils.flatten_dict(config) LOG.info("Using CONFIG values:") for x in flat_config: if "password" in x or "aprsd.web.users.admin" in x: - LOG.info("{} = XXXXXXXXXXXXXXXXXXX".format(x)) + LOG.info(f"{x} = XXXXXXXXXXXXXXXXXXX") else: - LOG.info("{} = {}".format(x, flat_config[x])) + LOG.info(f"{x} = {flat_config[x]}") got_ack = False got_response = False @@ -328,7 +330,7 @@ def listen( ), ) else: - LOG.debug("Not old enough to notify {} < {}".format(d, max_delta)) + LOG.debug(f"Not old enough to notify {d} < {max_delta}") LOG.debug("Update last seen from {}".format(packet["from"])) last_seen[packet["from"]] = now else: @@ -339,7 +341,7 @@ def listen( resp = packet.get("response", None) if resp == "ack": ack_num = packet.get("msgNo") - LOG.info("We saw an ACK {} Ignoring".format(ack_num)) + LOG.info(f"We saw an ACK {ack_num} Ignoring") # messaging.log_packet(packet) got_ack = True else: @@ -366,7 +368,7 @@ def listen( # LOG.debug("Filter by '{}'".format(filter_str)) # aprs_client.set_filter(filter_str) filter_str = "p/{}".format("/".join(watch_list)) - LOG.debug("Filter by '{}'".format(filter_str)) + LOG.debug(f"Filter by '{filter_str}'") aprs_client.set_filter(filter_str) while True: diff --git a/aprsd/main.py b/aprsd/main.py index b24ab2e..3017297 100644 --- a/aprsd/main.py +++ b/aprsd/main.py @@ -30,25 +30,19 @@ import signal import sys import time -# local imports here -import aprsd -from aprsd import ( - client, - email, - flask, - messaging, - packets, - plugin, - stats, - threads, - trace, - utils, -) import aprslib from aprslib.exceptions import LoginError import click import click_completion +# local imports here +import aprsd +from aprsd import ( + client, email, flask, messaging, packets, plugin, stats, threads, trace, + utils, +) + + # setup the global logger # logging.basicConfig(level=logging.DEBUG) # level=10 LOG = logging.getLogger("APRSD") @@ -90,7 +84,7 @@ Available shell types: %s Default type: auto """ % "\n ".join( - "{:<12} {}".format(k, click_completion.core.shells[k]) + f"{k:<12} {click_completion.core.shells[k]}" for k in sorted(click_completion.core.shells.keys()) ) @@ -152,7 +146,7 @@ def install(append, case_insensitive, shell, path): append=append, extra_env=extra_env, ) - click.echo("{} completion installed in {}".format(shell, path)) + click.echo(f"{shell} completion installed in {path}") def signal_handler(sig, frame): @@ -325,14 +319,14 @@ def send_message( messaging.CONFIG = config setup_logging(config, loglevel, quiet) - LOG.info("APRSD Started version: {}".format(aprsd.__version__)) + LOG.info(f"APRSD Started version: {aprsd.__version__}") if type(command) is tuple: command = " ".join(command) if not quiet: if raw: - LOG.info("L'{}' R'{}'".format(aprs_login, raw)) + LOG.info(f"L'{aprs_login}' R'{raw}'") else: - LOG.info("L'{}' To'{}' C'{}'".format(aprs_login, tocallsign, command)) + LOG.info(f"L'{aprs_login}' To'{tocallsign}' C'{command}'") got_ack = False got_response = False @@ -343,7 +337,7 @@ def send_message( resp = packet.get("response", None) if resp == "ack": ack_num = packet.get("msgNo") - LOG.info("We got ack for our sent message {}".format(ack_num)) + LOG.info(f"We got ack for our sent message {ack_num}") messaging.log_packet(packet) got_ack = True else: @@ -471,15 +465,15 @@ def server( LOG.warning(msg) else: LOG.info(msg) - LOG.info("APRSD Started version: {}".format(aprsd.__version__)) + LOG.info(f"APRSD Started version: {aprsd.__version__}") flat_config = utils.flatten_dict(config) LOG.info("Using CONFIG values:") for x in flat_config: if "password" in x or "aprsd.web.users.admin" in x: - LOG.info("{} = XXXXXXXXXXXXXXXXXXX".format(x)) + LOG.info(f"{x} = XXXXXXXXXXXXXXXXXXX") else: - LOG.info("{} = {}".format(x, flat_config[x])) + LOG.info(f"{x} = {flat_config[x]}") if config["aprsd"].get("trace", False): trace.setup_tracing(["method", "api"]) diff --git a/aprsd/messaging.py b/aprsd/messaging.py index 33595e7..09750e5 100644 --- a/aprsd/messaging.py +++ b/aprsd/messaging.py @@ -11,6 +11,7 @@ import time from aprsd import client, stats, threads, trace, utils + LOG = logging.getLogger("APRSD") # What to return from a plugin if we have processed the message @@ -81,7 +82,7 @@ class MsgTrack: with self.lock: result = "{" for key in self.track.keys(): - result += "{}: {}, ".format(key, str(self.track[key])) + result += f"{key}: {str(self.track[key])}, " result += "}" return result @@ -105,9 +106,9 @@ class MsgTrack: def save(self): """Save any queued to disk?""" - LOG.debug("Save tracker to disk? {}".format(len(self))) + LOG.debug(f"Save tracker to disk? {len(self)}") if len(self) > 0: - LOG.info("Saving {} tracking messages to disk".format(len(self))) + LOG.info(f"Saving {len(self)} tracking messages to disk") pickle.dump(self.dump(), open(utils.DEFAULT_SAVE_FILE, "wb+")) else: LOG.debug( @@ -239,7 +240,6 @@ class Message(metaclass=abc.ABCMeta): @abc.abstractmethod def send(self): """Child class must declare.""" - pass class RawMessage(Message): @@ -348,7 +348,7 @@ class TextMessage(Message): def send(self): tracker = MsgTrack() tracker.add(self) - LOG.debug("Length of MsgTrack is {}".format(len(tracker))) + LOG.debug(f"Length of MsgTrack is {len(tracker)}") thread = SendMessageThread(message=self) thread.start() @@ -370,7 +370,7 @@ class SendMessageThread(threads.APRSDThread): def __init__(self, message): self.msg = message name = self.msg.message[:5] - super().__init__("SendMessage-{}-{}".format(self.msg.id, name)) + super().__init__(f"SendMessage-{self.msg.id}-{name}") def loop(self): """Loop until a message is acked or it gets delayed. @@ -463,7 +463,7 @@ class AckMessage(Message): ) def send(self): - LOG.debug("Send ACK({}:{}) to radio.".format(self.tocall, self.id)) + LOG.debug(f"Send ACK({self.tocall}:{self.id}) to radio.") thread = SendAckThread(self) thread.start() @@ -486,7 +486,7 @@ class AckMessage(Message): class SendAckThread(threads.APRSDThread): def __init__(self, ack): self.ack = ack - super().__init__("SendAck-{}".format(self.ack.id)) + super().__init__(f"SendAck-{self.ack.id}") @trace.trace def loop(self): @@ -511,7 +511,7 @@ class SendAckThread(threads.APRSDThread): # It's time to try to send it again send_now = True else: - LOG.debug("Still wating. {}".format(delta)) + LOG.debug(f"Still wating. {delta}") else: send_now = True @@ -555,16 +555,8 @@ def log_packet(packet): def log_message( - header, - raw, - message, - tocall=None, - fromcall=None, - msg_num=None, - retry_number=None, - ack=None, - packet_type=None, - uuid=None, + header, raw, message, tocall=None, fromcall=None, msg_num=None, + retry_number=None, ack=None, packet_type=None, uuid=None, ): """ @@ -581,36 +573,36 @@ def log_message( log_list = [""] if retry_number: # LOG.info(" {} _______________(TX:{})".format(header, retry_number)) - log_list.append(" {} _______________(TX:{})".format(header, retry_number)) + log_list.append(f" {header} _______________(TX:{retry_number})") else: # LOG.info(" {} _______________".format(header)) - log_list.append(" {} _______________".format(header)) + log_list.append(f" {header} _______________") # LOG.info(" Raw : {}".format(raw)) - log_list.append(" Raw : {}".format(raw)) + log_list.append(f" Raw : {raw}") if packet_type: # LOG.info(" Packet : {}".format(packet_type)) - log_list.append(" Packet : {}".format(packet_type)) + log_list.append(f" Packet : {packet_type}") if tocall: # LOG.info(" To : {}".format(tocall)) - log_list.append(" To : {}".format(tocall)) + log_list.append(f" To : {tocall}") if fromcall: # LOG.info(" From : {}".format(fromcall)) - log_list.append(" From : {}".format(fromcall)) + log_list.append(f" From : {fromcall}") if ack: # LOG.info(" Ack : {}".format(ack)) - log_list.append(" Ack : {}".format(ack)) + log_list.append(f" Ack : {ack}") else: # LOG.info(" Message : {}".format(message)) - log_list.append(" Message : {}".format(message)) + log_list.append(f" Message : {message}") if msg_num: # LOG.info(" Msg number : {}".format(msg_num)) - log_list.append(" Msg number : {}".format(msg_num)) + log_list.append(f" Msg number : {msg_num}") if uuid: - log_list.append(" UUID : {}".format(uuid)) + log_list.append(f" UUID : {uuid}") # LOG.info(" {} _______________ Complete".format(header)) - log_list.append(" {} _______________ Complete".format(header)) + log_list.append(f" {header} _______________ Complete") LOG.info("\n".join(log_list)) diff --git a/aprsd/packets.py b/aprsd/packets.py index fe7d542..ae6e7d0 100644 --- a/aprsd/packets.py +++ b/aprsd/packets.py @@ -5,6 +5,7 @@ import time from aprsd import utils + LOG = logging.getLogger("APRSD") PACKET_TYPE_MESSAGE = "message" diff --git a/aprsd/plugin.py b/aprsd/plugin.py index 9d9c62f..f361827 100644 --- a/aprsd/plugin.py +++ b/aprsd/plugin.py @@ -11,6 +11,7 @@ import threading import pluggy from thesmuggler import smuggle + # setup the global logger LOG = logging.getLogger("APRSD") @@ -40,7 +41,6 @@ class APRSDCommandSpec: @hookspec def run(self, packet): """My special little hook that you can customize.""" - pass class APRSDNotificationPluginBase(metaclass=abc.ABCMeta): @@ -70,7 +70,6 @@ class APRSDNotificationPluginBase(metaclass=abc.ABCMeta): This will get called when a packet is seen by a callsign registered in the watch list in the config file.""" - pass class APRSDMessagePluginBase(metaclass=abc.ABCMeta): @@ -119,7 +118,6 @@ class APRSDMessagePluginBase(metaclass=abc.ABCMeta): To reply with a message over the air, return a string to send. """ - pass class PluginManager: @@ -152,7 +150,7 @@ class PluginManager: def load_plugins_from_path(self, module_path): if not os.path.exists(module_path): - LOG.error("plugin path '{}' doesn't exist.".format(module_path)) + LOG.error(f"plugin path '{module_path}' doesn't exist.") return None dir_path = os.path.realpath(module_path) @@ -163,8 +161,8 @@ class PluginManager: for path, _subdirs, files in os.walk(dir_path): for name in files: if fnmatch.fnmatch(name, pattern): - LOG.debug("MODULE? '{}' '{}'".format(name, path)) - module = smuggle("{}/{}".format(path, name)) + LOG.debug(f"MODULE? '{name}' '{path}'") + module = smuggle(f"{path}/{name}") for mem_name, obj in inspect.getmembers(module): if inspect.isclass(obj) and self.is_plugin(obj): self.obj_list.append( @@ -196,7 +194,7 @@ class PluginManager: module = importlib.import_module(module_name) module = importlib.reload(module) except Exception as ex: - LOG.error("Failed to load Plugin '{}' : '{}'".format(module_name, ex)) + LOG.error(f"Failed to load Plugin '{module_name}' : '{ex}'") return assert hasattr(module, class_name), "class {} is not in {}".format( @@ -238,7 +236,7 @@ class PluginManager: ) self._pluggy_msg_pm.register(plugin_obj) except Exception as ex: - LOG.exception("Couldn't load plugin '{}'".format(plugin_name), ex) + LOG.exception(f"Couldn't load plugin '{plugin_name}'", ex) def _load_notify_plugin(self, plugin_name): """ @@ -262,7 +260,7 @@ class PluginManager: ) self._pluggy_notify_pm.register(plugin_obj) except Exception as ex: - LOG.exception("Couldn't load plugin '{}'".format(plugin_name), ex) + LOG.exception(f"Couldn't load plugin '{plugin_name}'", ex) def reload_plugins(self): with self.lock: diff --git a/aprsd/plugin_utils.py b/aprsd/plugin_utils.py index d6af3b8..bad0bb3 100644 --- a/aprsd/plugin_utils.py +++ b/aprsd/plugin_utils.py @@ -4,11 +4,12 @@ import logging import requests + LOG = logging.getLogger("APRSD") def get_aprs_fi(api_key, callsign): - LOG.debug("Fetch aprs.fi location for '{}'".format(callsign)) + LOG.debug(f"Fetch aprs.fi location for '{callsign}'") try: url = ( "http://api.aprs.fi/api/get?" @@ -24,13 +25,13 @@ def get_aprs_fi(api_key, callsign): def get_weather_gov_for_gps(lat, lon): - LOG.debug("Fetch station at {}, {}".format(lat, lon)) + LOG.debug(f"Fetch station at {lat}, {lon}") try: url2 = ( "https://forecast.weather.gov/MapClick.php?lat=%s" "&lon=%s&FcstType=json" % (lat, lon) ) - LOG.debug("Fetching weather '{}'".format(url2)) + LOG.debug(f"Fetching weather '{url2}'") response = requests.get(url2) except Exception as e: LOG.error(e) @@ -41,7 +42,7 @@ def get_weather_gov_for_gps(lat, lon): def get_weather_gov_metar(station): - LOG.debug("Fetch metar for station '{}'".format(station)) + LOG.debug(f"Fetch metar for station '{station}'") try: url = "https://api.weather.gov/stations/{}/observations/latest".format( station, @@ -55,7 +56,7 @@ def get_weather_gov_metar(station): def fetch_openweathermap(api_key, lat, lon, units="metric", exclude=None): - LOG.debug("Fetch openweathermap for {}, {}".format(lat, lon)) + LOG.debug(f"Fetch openweathermap for {lat}, {lon}") if not exclude: exclude = "minutely,hourly,daily,alerts" try: diff --git a/aprsd/plugins/email.py b/aprsd/plugins/email.py index ead42e5..0d0d9c9 100644 --- a/aprsd/plugins/email.py +++ b/aprsd/plugins/email.py @@ -4,6 +4,7 @@ import time from aprsd import email, messaging, plugin, trace + LOG = logging.getLogger("APRSD") @@ -68,11 +69,11 @@ class EmailPlugin(plugin.APRSDMessagePluginBase): if timedelta < 300: # five minutes too_soon = 1 if not too_soon or ack == 0: - LOG.info("Send email '{}'".format(content)) + LOG.info(f"Send email '{content}'") send_result = email.send_email(to_addr, content) reply = messaging.NULL_MESSAGE if send_result != 0: - reply = "-{} failed".format(to_addr) + reply = f"-{to_addr} failed" # messaging.send_message(fromcall, "-" + to_addr + " failed") else: # clear email sent dictionary if somehow goes over 100 diff --git a/aprsd/plugins/fortune.py b/aprsd/plugins/fortune.py index 38bc415..27fe632 100644 --- a/aprsd/plugins/fortune.py +++ b/aprsd/plugins/fortune.py @@ -4,6 +4,7 @@ import subprocess from aprsd import plugin, trace + LOG = logging.getLogger("APRSD") @@ -45,7 +46,7 @@ class FortunePlugin(plugin.APRSDMessagePluginBase): .replace("\t", " ") ) except subprocess.CalledProcessError as ex: - reply = "Fortune command failed '{}'".format(ex.output) + reply = f"Fortune command failed '{ex.output}'" else: reply = output diff --git a/aprsd/plugins/location.py b/aprsd/plugins/location.py index d6eb5a7..a201a17 100644 --- a/aprsd/plugins/location.py +++ b/aprsd/plugins/location.py @@ -4,6 +4,7 @@ import time from aprsd import plugin, plugin_utils, trace, utils + LOG = logging.getLogger("APRSD") @@ -25,7 +26,7 @@ class LocationPlugin(plugin.APRSDMessagePluginBase): try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: - LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) + LOG.error(f"Failed to find config aprs.fi:apikey {ex}") return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] @@ -42,10 +43,10 @@ class LocationPlugin(plugin.APRSDMessagePluginBase): try: aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall) except Exception as ex: - LOG.error("Failed to fetch aprs.fi '{}'".format(ex)) + LOG.error(f"Failed to fetch aprs.fi '{ex}'") return "Failed to fetch aprs.fi location" - LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) + LOG.debug(f"LocationPlugin: aprs_data = {aprs_data}") if not len(aprs_data["entries"]): LOG.error("Didn't get any entries from aprs.fi") return "Failed to fetch aprs.fi location" @@ -67,11 +68,11 @@ class LocationPlugin(plugin.APRSDMessagePluginBase): try: wx_data = plugin_utils.get_weather_gov_for_gps(lat, lon) except Exception as ex: - LOG.error("Couldn't fetch forecast.weather.gov '{}'".format(ex)) + LOG.error(f"Couldn't fetch forecast.weather.gov '{ex}'") wx_data = {"location": {"areaDescription": "Unknown Location"}} if "location" not in wx_data: - LOG.error("Couldn't fetch forecast.weather.gov '{}'".format(wx_data)) + LOG.error(f"Couldn't fetch forecast.weather.gov '{wx_data}'") wx_data = {"location": {"areaDescription": "Unknown Location"}} reply = "{}: {} {}' {},{} {}h ago".format( diff --git a/aprsd/plugins/notify.py b/aprsd/plugins/notify.py index dd48500..0687020 100644 --- a/aprsd/plugins/notify.py +++ b/aprsd/plugins/notify.py @@ -2,6 +2,7 @@ import logging from aprsd import messaging, packets, plugin + LOG = logging.getLogger("APRSD") @@ -40,7 +41,7 @@ class NotifySeenPlugin(plugin.APRSDNotificationPluginBase): packet_type = packets.get_packet_type(packet) # we shouldn't notify the alert user that they are online. if fromcall != notify_callsign: - return "{} was just seen by type:'{}'".format(fromcall, packet_type) + return f"{fromcall} was just seen by type:'{packet_type}'" else: LOG.debug( "Not old enough to notify callsign '{}' : {} < {}".format( diff --git a/aprsd/plugins/ping.py b/aprsd/plugins/ping.py index 26e3cef..471bc07 100644 --- a/aprsd/plugins/ping.py +++ b/aprsd/plugins/ping.py @@ -3,6 +3,7 @@ import time from aprsd import plugin, trace + LOG = logging.getLogger("APRSD") diff --git a/aprsd/plugins/query.py b/aprsd/plugins/query.py index 780bc89..b6e3eb0 100644 --- a/aprsd/plugins/query.py +++ b/aprsd/plugins/query.py @@ -4,6 +4,7 @@ import re from aprsd import messaging, plugin, trace + LOG = logging.getLogger("APRSD") diff --git a/aprsd/plugins/stock.py b/aprsd/plugins/stock.py index 87c025e..83d487e 100644 --- a/aprsd/plugins/stock.py +++ b/aprsd/plugins/stock.py @@ -1,9 +1,11 @@ import logging import re -from aprsd import plugin, trace import yfinance as yf +from aprsd import plugin, trace + + LOG = logging.getLogger("APRSD") @@ -30,7 +32,7 @@ class StockPlugin(plugin.APRSDMessagePluginBase): reply = "No stock symbol" return reply - LOG.info("Fetch stock quote for '{}'".format(stock_symbol)) + LOG.info(f"Fetch stock quote for '{stock_symbol}'") try: stock = yf.Ticker(stock_symbol) @@ -42,8 +44,8 @@ class StockPlugin(plugin.APRSDMessagePluginBase): ) except Exception as e: LOG.error( - "Failed to fetch stock '{}' from yahoo '{}'".format(stock_symbol, e), + f"Failed to fetch stock '{stock_symbol}' from yahoo '{e}'", ) - reply = "Failed to fetch stock '{}'".format(stock_symbol) + reply = f"Failed to fetch stock '{stock_symbol}'" return reply.rstrip() diff --git a/aprsd/plugins/time.py b/aprsd/plugins/time.py index f71b09d..819e657 100644 --- a/aprsd/plugins/time.py +++ b/aprsd/plugins/time.py @@ -2,10 +2,12 @@ import logging import re import time -from aprsd import fuzzyclock, plugin, plugin_utils, trace, utils from opencage.geocoder import OpenCageGeocode import pytz +from aprsd import fuzzyclock, plugin, plugin_utils, trace, utils + + LOG = logging.getLogger("APRSD") @@ -64,7 +66,7 @@ class TimeOpenCageDataPlugin(TimePlugin): try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: - LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) + LOG.error(f"Failed to find config aprs.fi:apikey {ex}") return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] @@ -81,7 +83,7 @@ class TimeOpenCageDataPlugin(TimePlugin): try: aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall) except Exception as ex: - LOG.error("Failed to fetch aprs.fi data {}".format(ex)) + LOG.error(f"Failed to fetch aprs.fi data {ex}") return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) @@ -95,7 +97,7 @@ class TimeOpenCageDataPlugin(TimePlugin): try: utils.check_config_option(self.config, "opencagedata", "apiKey") except Exception as ex: - LOG.error("Failed to find config opencage:apiKey {}".format(ex)) + LOG.error(f"Failed to find config opencage:apiKey {ex}") return "No opencage apiKey found" try: @@ -103,7 +105,7 @@ class TimeOpenCageDataPlugin(TimePlugin): geocoder = OpenCageGeocode(opencage_key) results = geocoder.reverse_geocode(lat, lon) except Exception as ex: - LOG.error("Couldn't fetch opencagedata api '{}'".format(ex)) + LOG.error(f"Couldn't fetch opencagedata api '{ex}'") # Default to UTC instead localzone = pytz.timezone("UTC") else: @@ -130,7 +132,7 @@ class TimeOWMPlugin(TimePlugin): try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: - LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) + LOG.error(f"Failed to find config aprs.fi:apikey {ex}") return "No aprs.fi apikey found" # optional second argument is a callsign to search @@ -146,10 +148,10 @@ class TimeOWMPlugin(TimePlugin): try: aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall) except Exception as ex: - LOG.error("Failed to fetch aprs.fi data {}".format(ex)) + LOG.error(f"Failed to fetch aprs.fi data {ex}") return "Failed to fetch location" - LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) + LOG.debug(f"LocationPlugin: aprs_data = {aprs_data}") if not len(aprs_data["entries"]): LOG.error("Didn't get any entries from aprs.fi") return "Failed to fetch aprs.fi location" @@ -163,14 +165,14 @@ class TimeOWMPlugin(TimePlugin): ["services", "openweathermap", "apiKey"], ) except Exception as ex: - LOG.error("Failed to find config openweathermap:apiKey {}".format(ex)) + LOG.error(f"Failed to find config openweathermap:apiKey {ex}") return "No openweathermap apiKey found" api_key = self.config["services"]["openweathermap"]["apiKey"] try: results = plugin_utils.fetch_openweathermap(api_key, lat, lon) except Exception as ex: - LOG.error("Couldn't fetch openweathermap api '{}'".format(ex)) + LOG.error(f"Couldn't fetch openweathermap api '{ex}'") # default to UTC localzone = pytz.timezone("UTC") else: diff --git a/aprsd/plugins/version.py b/aprsd/plugins/version.py index 2619e49..cad661d 100644 --- a/aprsd/plugins/version.py +++ b/aprsd/plugins/version.py @@ -3,6 +3,7 @@ import logging import aprsd from aprsd import plugin, stats, trace + LOG = logging.getLogger("APRSD") diff --git a/aprsd/plugins/weather.py b/aprsd/plugins/weather.py index bdedd08..6f94c45 100644 --- a/aprsd/plugins/weather.py +++ b/aprsd/plugins/weather.py @@ -2,9 +2,11 @@ import json import logging import re -from aprsd import plugin, plugin_utils, trace, utils import requests +from aprsd import plugin, plugin_utils, trace, utils + + LOG = logging.getLogger("APRSD") @@ -34,14 +36,14 @@ class USWeatherPlugin(plugin.APRSDMessagePluginBase): try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: - LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) + LOG.error(f"Failed to find config aprs.fi:apikey {ex}") return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] try: aprs_data = plugin_utils.get_aprs_fi(api_key, fromcall) except Exception as ex: - LOG.error("Failed to fetch aprs.fi data {}".format(ex)) + LOG.error(f"Failed to fetch aprs.fi data {ex}") return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) @@ -51,7 +53,7 @@ class USWeatherPlugin(plugin.APRSDMessagePluginBase): try: wx_data = plugin_utils.get_weather_gov_for_gps(lat, lon) except Exception as ex: - LOG.error("Couldn't fetch forecast.weather.gov '{}'".format(ex)) + LOG.error(f"Couldn't fetch forecast.weather.gov '{ex}'") return "Unable to get weather" reply = ( @@ -65,7 +67,7 @@ class USWeatherPlugin(plugin.APRSDMessagePluginBase): wx_data["data"]["weather"][1], ) ).rstrip() - LOG.debug("reply: '{}' ".format(reply)) + LOG.debug(f"reply: '{reply}' ") return reply @@ -93,7 +95,7 @@ class USMetarPlugin(plugin.APRSDMessagePluginBase): fromcall = packet.get("from") message = packet.get("message_text", None) # ack = packet.get("msgNo", "0") - LOG.info("WX Plugin '{}'".format(message)) + LOG.info(f"WX Plugin '{message}'") a = re.search(r"^.*\s+(.*)", message) if a is not None: searchcall = a.group(1) @@ -101,7 +103,7 @@ class USMetarPlugin(plugin.APRSDMessagePluginBase): try: resp = plugin_utils.get_weather_gov_metar(station) except Exception as e: - LOG.debug("Weather failed with: {}".format(str(e))) + LOG.debug(f"Weather failed with: {str(e)}") reply = "Unable to find station METAR" else: station_data = json.loads(resp.text) @@ -118,7 +120,7 @@ class USMetarPlugin(plugin.APRSDMessagePluginBase): ["services", "aprs.fi", "apiKey"], ) except Exception as ex: - LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) + LOG.error(f"Failed to find config aprs.fi:apikey {ex}") return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] @@ -126,7 +128,7 @@ class USMetarPlugin(plugin.APRSDMessagePluginBase): try: aprs_data = plugin_utils.get_aprs_fi(api_key, fromcall) except Exception as ex: - LOG.error("Failed to fetch aprs.fi data {}".format(ex)) + LOG.error(f"Failed to fetch aprs.fi data {ex}") return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) @@ -140,7 +142,7 @@ class USMetarPlugin(plugin.APRSDMessagePluginBase): try: wx_data = plugin_utils.get_weather_gov_for_gps(lat, lon) except Exception as ex: - LOG.error("Couldn't fetch forecast.weather.gov '{}'".format(ex)) + LOG.error(f"Couldn't fetch forecast.weather.gov '{ex}'") return "Unable to metar find station." if wx_data["location"]["metar"]: @@ -148,7 +150,7 @@ class USMetarPlugin(plugin.APRSDMessagePluginBase): try: resp = plugin_utils.get_weather_gov_metar(station) except Exception as e: - LOG.debug("Weather failed with: {}".format(str(e))) + LOG.debug(f"Weather failed with: {str(e)}") reply = "Failed to get Metar" else: station_data = json.loads(resp.text) @@ -188,7 +190,7 @@ class OWMWeatherPlugin(plugin.APRSDMessagePluginBase): fromcall = packet.get("from") message = packet.get("message_text", None) # ack = packet.get("msgNo", "0") - LOG.info("OWMWeather Plugin '{}'".format(message)) + LOG.info(f"OWMWeather Plugin '{message}'") a = re.search(r"^.*\s+(.*)", message) if a is not None: searchcall = a.group(1) @@ -199,14 +201,14 @@ class OWMWeatherPlugin(plugin.APRSDMessagePluginBase): try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: - LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) + LOG.error(f"Failed to find config aprs.fi:apikey {ex}") return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] try: aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall) except Exception as ex: - LOG.error("Failed to fetch aprs.fi data {}".format(ex)) + LOG.error(f"Failed to fetch aprs.fi data {ex}") return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) @@ -223,7 +225,7 @@ class OWMWeatherPlugin(plugin.APRSDMessagePluginBase): ["services", "openweathermap", "apiKey"], ) except Exception as ex: - LOG.error("Failed to find config openweathermap:apiKey {}".format(ex)) + LOG.error(f"Failed to find config openweathermap:apiKey {ex}") return "No openweathermap apiKey found" try: @@ -244,7 +246,7 @@ class OWMWeatherPlugin(plugin.APRSDMessagePluginBase): exclude="minutely,hourly", ) except Exception as ex: - LOG.error("Couldn't fetch openweathermap api '{}'".format(ex)) + LOG.error(f"Couldn't fetch openweathermap api '{ex}'") # default to UTC return "Unable to get weather" @@ -312,7 +314,7 @@ class AVWXWeatherPlugin(plugin.APRSDMessagePluginBase): fromcall = packet.get("from") message = packet.get("message_text", None) # ack = packet.get("msgNo", "0") - LOG.info("OWMWeather Plugin '{}'".format(message)) + LOG.info(f"OWMWeather Plugin '{message}'") a = re.search(r"^.*\s+(.*)", message) if a is not None: searchcall = a.group(1) @@ -323,14 +325,14 @@ class AVWXWeatherPlugin(plugin.APRSDMessagePluginBase): try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: - LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) + LOG.error(f"Failed to find config aprs.fi:apikey {ex}") return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] try: aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall) except Exception as ex: - LOG.error("Failed to fetch aprs.fi data {}".format(ex)) + LOG.error(f"Failed to fetch aprs.fi data {ex}") return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) @@ -344,32 +346,32 @@ class AVWXWeatherPlugin(plugin.APRSDMessagePluginBase): try: utils.check_config_option(self.config, ["services", "avwx", "apiKey"]) except Exception as ex: - LOG.error("Failed to find config avwx:apiKey {}".format(ex)) + LOG.error(f"Failed to find config avwx:apiKey {ex}") return "No avwx apiKey found" try: utils.check_config_option(self.config, ["services", "avwx", "base_url"]) except Exception as ex: - LOG.debug("Didn't find avwx:base_url {}".format(ex)) + LOG.debug(f"Didn't find avwx:base_url {ex}") base_url = "https://avwx.rest" else: base_url = self.config["services"]["avwx"]["base_url"] api_key = self.config["services"]["avwx"]["apiKey"] - token = "TOKEN {}".format(api_key) + token = f"TOKEN {api_key}" headers = {"Authorization": token} try: - coord = "{},{}".format(lat, lon) + coord = f"{lat},{lon}" url = ( "{}/api/station/near/{}?" "n=1&airport=false&reporting=true&format=json".format(base_url, coord) ) - LOG.debug("Get stations near me '{}'".format(url)) + LOG.debug(f"Get stations near me '{url}'") response = requests.get(url, headers=headers) except Exception as ex: LOG.error(ex) - raise Exception("Failed to get the weather '{}'".format(ex)) + raise Exception(f"Failed to get the weather '{ex}'") else: wx_data = json.loads(response.text) @@ -385,11 +387,11 @@ class AVWXWeatherPlugin(plugin.APRSDMessagePluginBase): ) ) - LOG.debug("Get METAR '{}'".format(url)) + LOG.debug(f"Get METAR '{url}'") response = requests.get(url, headers=headers) except Exception as ex: LOG.error(ex) - raise Exception("Failed to get metar {}".format(ex)) + raise Exception(f"Failed to get metar {ex}") else: metar_data = json.loads(response.text) diff --git a/aprsd/stats.py b/aprsd/stats.py index de5a226..d70ab8d 100644 --- a/aprsd/stats.py +++ b/aprsd/stats.py @@ -5,6 +5,7 @@ import threading import aprsd from aprsd import packets, plugin, utils + LOG = logging.getLogger("APRSD") diff --git a/aprsd/threads.py b/aprsd/threads.py index e2d21ec..60fec15 100644 --- a/aprsd/threads.py +++ b/aprsd/threads.py @@ -6,9 +6,11 @@ import threading import time import tracemalloc -from aprsd import client, messaging, packets, plugin, stats, utils import aprslib +from aprsd import client, messaging, packets, plugin, stats, utils + + LOG = logging.getLogger("APRSD") RX_THREAD = "RX" @@ -214,7 +216,7 @@ class APRSDRXThread(APRSDThread): def process_ack_packet(self, packet): ack_num = packet.get("msgNo") - LOG.info("Got ack for message {}".format(ack_num)) + LOG.info(f"Got ack for message {ack_num}") messaging.log_message( "ACK", packet["raw"], @@ -257,7 +259,7 @@ class APRSDRXThread(APRSDThread): # one of the plugins wants to send multiple messages found_command = True for subreply in reply: - LOG.debug("Sending '{}'".format(subreply)) + LOG.debug(f"Sending '{subreply}'") msg = messaging.TextMessage( self.config["aprs"]["login"], @@ -272,7 +274,7 @@ class APRSDRXThread(APRSDThread): # us that they processed the message correctly, but have # nothing to reply with, so we avoid replying with a usage string if reply is not messaging.NULL_MESSAGE: - LOG.debug("Sending '{}'".format(reply)) + LOG.debug(f"Sending '{reply}'") msg = messaging.TextMessage( self.config["aprs"]["login"], diff --git a/aprsd/trace.py b/aprsd/trace.py index 3b985e2..185d00b 100644 --- a/aprsd/trace.py +++ b/aprsd/trace.py @@ -5,6 +5,7 @@ import logging import time import types + VALID_TRACE_FLAGS = {"method", "api"} TRACE_API = False TRACE_METHOD = False @@ -155,8 +156,6 @@ class TraceWrapperMetaclass(type): class TraceWrapperWithABCMetaclass(abc.ABCMeta, TraceWrapperMetaclass): """Metaclass that wraps all methods of a class with trace.""" - pass - def setup_tracing(trace_flags): """Set global variables for each trace flag. diff --git a/aprsd/utils.py b/aprsd/utils.py index 0e3255c..3793b90 100644 --- a/aprsd/utils.py +++ b/aprsd/utils.py @@ -10,12 +10,14 @@ import re import sys import threading -import aprsd -from aprsd import plugin import click import update_checker import yaml +import aprsd +from aprsd import plugin + + LOG_LEVELS = { "CRITICAL": logging.CRITICAL, "ERROR": logging.ERROR, @@ -102,9 +104,9 @@ DEFAULT_CONFIG_DICT = { } home = str(Path.home()) -DEFAULT_CONFIG_DIR = "{}/.config/aprsd/".format(home) -DEFAULT_SAVE_FILE = "{}/.config/aprsd/aprsd.p".format(home) -DEFAULT_CONFIG_FILE = "{}/.config/aprsd/aprsd.yml".format(home) +DEFAULT_CONFIG_DIR = f"{home}/.config/aprsd/" +DEFAULT_SAVE_FILE = f"{home}/.config/aprsd/aprsd.p" +DEFAULT_CONFIG_FILE = f"{home}/.config/aprsd/aprsd.yml" def synchronized(wrapped): @@ -229,7 +231,7 @@ def create_default_config(): config_file_expanded = os.path.expanduser(DEFAULT_CONFIG_FILE) config_dir = os.path.dirname(config_file_expanded) if not os.path.exists(config_dir): - click.echo("Config dir '{}' doesn't exist, creating.".format(config_dir)) + click.echo(f"Config dir '{config_dir}' doesn't exist, creating.") mkdir_p(config_dir) with open(config_file_expanded, "w+") as cf: cf.write(dump_default_cfg()) @@ -245,7 +247,7 @@ def get_config(config_file): else: if config_file == DEFAULT_CONFIG_FILE: click.echo( - "{} is missing, creating config file".format(config_file_expanded), + f"{config_file_expanded} is missing, creating config file", ) create_default_config() msg = ( @@ -256,7 +258,7 @@ def get_config(config_file): else: # The user provided a config file path different from the # Default, so we won't try and create it, just bitch and bail. - msg = "Custom config file '{}' is missing.".format(config_file) + msg = f"Custom config file '{config_file}' is missing." click.echo(msg) sys.exit(-1) diff --git a/dev-requirements.in b/dev-requirements.in index 3b57009..e12700c 100644 --- a/dev-requirements.in +++ b/dev-requirements.in @@ -1,4 +1,3 @@ -black flake8 isort mypy @@ -10,3 +9,4 @@ tox twine pre-commit pip-tools +gray diff --git a/dev-requirements.txt b/dev-requirements.txt index af7dba9..e3141af 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -4,6 +4,8 @@ # # pip-compile dev-requirements.in # +add-trailing-comma==2.1.0 + # via gray alabaster==0.7.12 # via sphinx appdirs==1.4.4 @@ -11,17 +13,19 @@ appdirs==1.4.4 # black # virtualenv attrs==20.3.0 - # via pytest + # via + # jsonschema + # pytest +autoflake==1.4 + # via gray babel==2.9.1 # via sphinx -black==21.4b2 - # via -r dev-requirements.in +black==21.7b0 + # via gray bleach==3.3.0 # via readme-renderer certifi==2020.12.5 # via requests -cffi==1.14.5 - # via cryptography cfgv==3.2.0 # via pre-commit chardet==4.0.0 @@ -32,26 +36,35 @@ click==7.1.2 # pip-tools colorama==0.4.4 # via twine +colorlog==6.4.1 + # via prettylog +configargparse==1.5.2 + # via gray coverage==5.5 # via pytest-cov -cryptography==3.4.7 - # via secretstorage distlib==0.3.1 # via virtualenv docutils==0.16 # via # readme-renderer # sphinx +fast-json==0.3.2 + # via prettylog filelock==3.0.12 # via # tox # virtualenv +fixit==0.1.4 + # via gray flake8-polyfill==1.0.2 # via pep8-naming flake8==3.9.1 # via # -r dev-requirements.in + # fixit # flake8-polyfill +gray==0.10.1 + # via -r dev-requirements.in identify==2.2.4 # via pre-commit idna==2.10 @@ -62,18 +75,22 @@ importlib-metadata==4.0.1 # via # keyring # twine +importlib-resources==5.2.2 + # via fixit iniconfig==1.1.1 # via pytest isort==5.8.0 - # via -r dev-requirements.in -jeepney==0.6.0 # via - # keyring - # secretstorage + # -r dev-requirements.in + # gray jinja2==2.11.3 # via sphinx +jsonschema==3.2.0 + # via fixit keyring==23.0.1 # via twine +libcst==0.3.20 + # via fixit markupsafe==1.1.1 # via jinja2 mccabe==0.6.1 @@ -82,6 +99,7 @@ mypy-extensions==0.4.3 # via # black # mypy + # typing-inspect mypy==0.812 # via -r dev-requirements.in nodeenv==1.6.0 @@ -108,22 +126,26 @@ pluggy==0.13.1 # tox pre-commit==2.12.1 # via -r dev-requirements.in +prettylog==0.3.0 + # via gray py==1.10.0 # via # pytest # tox pycodestyle==2.7.0 # via flake8 -pycparser==2.20 - # via cffi pyflakes==2.3.1 - # via flake8 + # via + # autoflake + # flake8 pygments==2.9.0 # via # readme-renderer # sphinx pyparsing==2.4.7 # via packaging +pyrsistent==0.18.0 + # via jsonschema pytest-cov==2.11.1 # via -r dev-requirements.in pytest==6.2.3 @@ -132,8 +154,13 @@ pytest==6.2.3 # pytest-cov pytz==2021.1 # via babel +pyupgrade==2.24.0 + # via gray pyyaml==5.4.1 - # via pre-commit + # via + # fixit + # libcst + # pre-commit readme-renderer==29.0 # via twine regex==2021.4.4 @@ -147,11 +174,10 @@ requests==2.25.1 # twine rfc3986==1.4.0 # via twine -secretstorage==3.3.1 - # via keyring six==1.15.0 # via # bleach + # jsonschema # readme-renderer # tox # virtualenv @@ -171,13 +197,18 @@ sphinxcontrib-qthelp==1.0.3 # via sphinx sphinxcontrib-serializinghtml==1.1.4 # via sphinx +tokenize-rt==4.1.0 + # via + # add-trailing-comma + # pyupgrade toml==0.10.2 # via - # black # pep517 # pre-commit # pytest # tox +tomli==1.2.1 + # via black tox==3.23.0 # via -r dev-requirements.in tqdm==4.60.0 @@ -187,7 +218,18 @@ twine==3.4.1 typed-ast==1.4.3 # via mypy typing-extensions==3.10.0.0 - # via mypy + # via + # libcst + # mypy + # typing-inspect +typing-inspect==0.7.1 + # via libcst +ujson==4.1.0 + # via fast-json +unify==0.5 + # via gray +untokenize==0.1.1 + # via unify urllib3==1.26.5 # via requests virtualenv==20.4.4 @@ -197,7 +239,9 @@ virtualenv==20.4.4 webencodings==0.5.1 # via bleach zipp==3.4.1 - # via importlib-metadata + # via + # importlib-metadata + # importlib-resources # The following packages are considered to be unsafe in a requirements file: # pip diff --git a/docs/conf.py b/docs/conf.py index b71f155..9e2a75c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,7 @@ import os import sys + sys.path.insert(0, os.path.abspath("../src")) diff --git a/examples/plugins/example_plugin.py b/examples/plugins/example_plugin.py index c4eb1d0..d674d0d 100644 --- a/examples/plugins/example_plugin.py +++ b/examples/plugins/example_plugin.py @@ -2,6 +2,7 @@ import logging from aprsd import plugin + LOG = logging.getLogger("APRSD") @@ -15,5 +16,5 @@ class HelloPlugin(plugin.APRSDPluginBase): def command(self, fromcall, message, ack): LOG.info("HelloPlugin") - reply = "Hello '{}'".format(fromcall) + reply = f"Hello '{fromcall}'" return reply diff --git a/gray.conf b/gray.conf new file mode 100644 index 0000000..9dbc59d --- /dev/null +++ b/gray.conf @@ -0,0 +1,2 @@ +formatters = add-trailing-comma,autoflake,fixit,isort,pyupgrade,unify +min-python-version = 3.8 diff --git a/pyproject.toml b/pyproject.toml index 09592fb..731042d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,32 +2,12 @@ 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 +multi_line_output = 4 +line_length = 88 # Inform isort of paths to import names that should be considered part of the "First Party" group. -src_paths = ["src/openstack_loadtest"] +#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. diff --git a/setup.py b/setup.py index 90623e2..042f113 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT import setuptools + # In python < 2.7.4, a lazy loading of package `pbr` will break # setuptools if some other modules registered functions in `atexit`. # solution from: http://bugs.python.org/issue15881#msg170215 diff --git a/tests/test_email.py b/tests/test_email.py index 77a1c6d..08a35e2 100644 --- a/tests/test_email.py +++ b/tests/test_email.py @@ -7,7 +7,7 @@ class TestEmail(unittest.TestCase): def test_get_email_from_shortcut(self): email.CONFIG = {"aprsd": {"email": {"shortcuts": {}}}} email_address = "something@something.com" - addr = "-{}".format(email_address) + addr = f"-{email_address}" actual = email.get_email_from_shortcut(addr) self.assertEqual(addr, actual) diff --git a/tests/test_main.py b/tests/test_main.py index 7996fcd..a140131 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -3,6 +3,7 @@ import unittest from aprsd import email + if sys.version_info >= (3, 2): from unittest import mock else: diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 2acf70b..8ee2cd7 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -1,6 +1,8 @@ import unittest from unittest import mock +import pytz + import aprsd from aprsd import messaging, stats, utils from aprsd.fuzzyclock import fuzzy @@ -9,7 +11,6 @@ from aprsd.plugins import ping as ping_plugin from aprsd.plugins import query as query_plugin from aprsd.plugins import time as time_plugin from aprsd.plugins import version as version_plugin -import pytz class TestPlugin(unittest.TestCase): @@ -171,7 +172,7 @@ class TestPlugin(unittest.TestCase): @mock.patch("aprsd.plugin.PluginManager.get_msg_plugins") def test_version(self, mock_get_plugins): - expected = "APRSD ver:{} uptime:0:0:0".format(aprsd.__version__) + expected = f"APRSD ver:{aprsd.__version__} uptime:0:0:0" version = version_plugin.VersionPlugin(self.config) packet = self.fake_packet( diff --git a/tox.ini b/tox.ini index dc48f07..0a415d1 100644 --- a/tox.ini +++ b/tox.ini @@ -76,9 +76,9 @@ exclude = .venv,.git,.tox,dist,doc,.ropeproject # This section is not needed if not using GitHub Actions for CI. [gh-actions] python = - 3.6: py36, pep8, fmt-check - 3.7: py38, pep8, fmt-check - 3.8: py38, pep8, fmt-check, type-check, docs + 3.6: py36, pep8 + 3.7: py38, pep8 + 3.8: py38, pep8, type-check, docs 3.9: py39 [testenv:fmt] @@ -88,19 +88,7 @@ skip_install = true deps = -r{toxinidir}/dev-requirements.txt commands = - isort . - black . - -[testenv:fmt-check] -# Runs a check only on code formatting. -# you can fix imports by running isort standalone -# you can fix code formatting by running black standalone -skip_install = true -deps = - -r{toxinidir}/dev-requirements.txt -commands = - isort --check-only . - black --check . + gray aprsd tests [testenv:type-check] skip_install = true