From f15974131c4b55f1c4c1085f4d78d6e179da7157 Mon Sep 17 00:00:00 2001
From: Hemna <waboring@hemna.com>
Date: Tue, 14 May 2024 11:16:29 -0400
Subject: [PATCH] Eliminate need for PBR

This patch also removes the setup.cfg and replaces it with
the pyproject.toml.

This also renames the dev-requirements.txt to requirements-dev.txt

To install dev
pip install -e ".[dev]"
---
 ChangeLog                                  |   2 +
 Makefile                                   |   9 +-
 aprsd/__init__.py                          |   7 +-
 dev-requirements.txt                       | 209 -----------------
 pyproject.toml                             | 161 ++++++++++++-
 dev-requirements.in => requirements-dev.in |  16 +-
 requirements-dev.txt                       |  84 +++++++
 requirements.in                            |  58 +++--
 requirements.txt                           | 249 ++++++---------------
 setup.cfg                                  |  51 -----
 setup.py                                   |  10 +-
 tox.ini                                    |  10 +-
 12 files changed, 369 insertions(+), 497 deletions(-)
 delete mode 100644 dev-requirements.txt
 rename dev-requirements.in => requirements-dev.in (88%)
 create mode 100644 requirements-dev.txt
 delete mode 100644 setup.cfg

diff --git a/ChangeLog b/ChangeLog
index 01fd2df..1c9fdca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,8 @@
 CHANGES
 =======
 
+* Put an upper bound on the QueueHandler queue
+
 v3.4.0
 ------
 
diff --git a/Makefile b/Makefile
index 1dc0e5c..9df9a70 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ Makefile.venv:
 help:	# Help for the Makefile
 	@egrep -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
 
-dev: REQUIREMENTS_TXT = requirements.txt dev-requirements.txt
+dev: REQUIREMENTS_TXT = requirements.txt requirements-dev.txt
 dev: venv  ## Create a python virtual environment for development of aprsd
 
 run: venv  ## Create a virtual environment for running aprsd commands
@@ -39,7 +39,6 @@ clean-build: ## remove build artifacts
 clean-pyc: ## remove Python file artifacts
 	find . -name '*.pyc' -exec rm -f {} +
 	find . -name '*.pyo' -exec rm -f {} +
-	find . -name '*~' -exec rm -f {} +
 	find . -name '__pycache__' -exec rm -fr {} +
 
 clean-test: ## remove test and coverage artifacts
@@ -81,8 +80,8 @@ docker-dev: test  ## Make a development docker container tagged with hemna6969/a
 
 update-requirements: dev  ## Update the requirements.txt and dev-requirements.txt files
 	rm requirements.txt
-	rm dev-requirements.txt
+	rm requirements-dev.txt
 	touch requirements.txt
-	touch dev-requirements.txt
+	touch requirements-dev.txt
 	$(VENV)/pip-compile --resolver backtracking --annotation-style=line requirements.in
-	$(VENV)/pip-compile --resolver backtracking --annotation-style=line dev-requirements.in
+	$(VENV)/pip-compile --resolver backtracking --annotation-style=line requirements-dev.in
diff --git a/aprsd/__init__.py b/aprsd/__init__.py
index 9f55804..b265032 100644
--- a/aprsd/__init__.py
+++ b/aprsd/__init__.py
@@ -10,7 +10,10 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import pbr.version
+from importlib.metadata import PackageNotFoundError, version
 
 
-__version__ = pbr.version.VersionInfo("aprsd").version_string()
+try:
+    __version__ = version("aprsd")
+except PackageNotFoundError:
+    pass
diff --git a/dev-requirements.txt b/dev-requirements.txt
deleted file mode 100644
index 3eb28c3..0000000
--- a/dev-requirements.txt
+++ /dev/null
@@ -1,209 +0,0 @@
-#
-# This file is autogenerated by pip-compile with Python 3.10
-# by the following command:
-#
-#    pip-compile --annotation-style=line dev-requirements.in
-#
-add-trailing-comma==3.1.0
-    # via gray
-alabaster==0.7.16
-    # via sphinx
-autoflake==1.5.3
-    # via gray
-babel==2.14.0
-    # via sphinx
-black==24.4.0
-    # via gray
-build==1.2.1
-    # via pip-tools
-cachetools==5.3.3
-    # via tox
-certifi==2024.2.2
-    # via requests
-cfgv==3.4.0
-    # via pre-commit
-chardet==5.2.0
-    # via tox
-charset-normalizer==3.3.2
-    # via requests
-click==8.1.7
-    # via
-    #   black
-    #   fixit
-    #   moreorless
-    #   pip-tools
-colorama==0.4.6
-    # via tox
-commonmark==0.9.1
-    # via rich
-configargparse==1.7
-    # via gray
-coverage[toml]==7.5.0
-    # via pytest-cov
-distlib==0.3.8
-    # via virtualenv
-docutils==0.21.2
-    # via sphinx
-exceptiongroup==1.2.1
-    # via pytest
-filelock==3.13.4
-    # via
-    #   tox
-    #   virtualenv
-fixit==2.1.0
-    # via gray
-flake8==7.0.0
-    # via
-    #   -r dev-requirements.in
-    #   pep8-naming
-gray==0.14.0
-    # via -r dev-requirements.in
-identify==2.5.36
-    # via pre-commit
-idna==3.7
-    # via requests
-imagesize==1.4.1
-    # via sphinx
-iniconfig==2.0.0
-    # via pytest
-isort==5.13.2
-    # via
-    #   -r dev-requirements.in
-    #   gray
-jinja2==3.1.4
-    # via sphinx
-libcst==1.3.1
-    # via fixit
-markupsafe==2.1.5
-    # via jinja2
-mccabe==0.7.0
-    # via flake8
-moreorless==0.4.0
-    # via fixit
-mypy==1.9.0
-    # via -r dev-requirements.in
-mypy-extensions==1.0.0
-    # via
-    #   black
-    #   mypy
-nodeenv==1.8.0
-    # via pre-commit
-packaging==24.0
-    # via
-    #   black
-    #   build
-    #   fixit
-    #   pyproject-api
-    #   pytest
-    #   sphinx
-    #   tox
-pathspec==0.12.1
-    # via
-    #   black
-    #   trailrunner
-pep8-naming==0.13.3
-    # via -r dev-requirements.in
-pip-tools==7.4.1
-    # via -r dev-requirements.in
-platformdirs==4.2.1
-    # via
-    #   black
-    #   tox
-    #   virtualenv
-pluggy==1.5.0
-    # via
-    #   pytest
-    #   tox
-pre-commit==3.7.0
-    # via -r dev-requirements.in
-pycodestyle==2.11.1
-    # via flake8
-pyflakes==3.2.0
-    # via
-    #   autoflake
-    #   flake8
-pygments==2.17.2
-    # via
-    #   rich
-    #   sphinx
-pyproject-api==1.6.1
-    # via tox
-pyproject-hooks==1.0.0
-    # via
-    #   build
-    #   pip-tools
-pytest==8.1.1
-    # via
-    #   -r dev-requirements.in
-    #   pytest-cov
-pytest-cov==5.0.0
-    # via -r dev-requirements.in
-pyupgrade==3.15.2
-    # via gray
-pyyaml==6.0.1
-    # via
-    #   libcst
-    #   pre-commit
-requests==2.31.0
-    # via sphinx
-rich==12.6.0
-    # via gray
-snowballstemmer==2.2.0
-    # via sphinx
-sphinx==7.3.7
-    # via -r dev-requirements.in
-sphinxcontrib-applehelp==1.0.8
-    # via sphinx
-sphinxcontrib-devhelp==1.0.6
-    # via sphinx
-sphinxcontrib-htmlhelp==2.0.5
-    # via sphinx
-sphinxcontrib-jsmath==1.0.1
-    # via sphinx
-sphinxcontrib-qthelp==1.0.7
-    # via sphinx
-sphinxcontrib-serializinghtml==1.1.10
-    # via sphinx
-tokenize-rt==5.2.0
-    # via
-    #   add-trailing-comma
-    #   pyupgrade
-toml==0.10.2
-    # via autoflake
-tomli==2.0.1
-    # via
-    #   black
-    #   build
-    #   coverage
-    #   fixit
-    #   mypy
-    #   pip-tools
-    #   pyproject-api
-    #   pyproject-hooks
-    #   pytest
-    #   sphinx
-    #   tox
-tox==4.14.2
-    # via -r dev-requirements.in
-trailrunner==1.4.0
-    # via fixit
-typing-extensions==4.11.0
-    # via
-    #   black
-    #   mypy
-unify==0.5
-    # via gray
-untokenize==0.1.1
-    # via unify
-urllib3==2.2.1
-    # via requests
-virtualenv==20.26.0
-    # via
-    #   pre-commit
-    #   tox
-wheel==0.43.0
-    # via pip-tools
-
-# The following packages are considered to be unsafe in a requirements file:
-# pip
-# setuptools
diff --git a/pyproject.toml b/pyproject.toml
index 731042d..398e176 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,5 +1,162 @@
+[project]
+
+# This is the name of your project. The first time you publish this
+# package, this name will be registered for you. It will determine how
+# users can install this project, e.g.:
+#
+# $ pip install sampleproject
+#
+# And where it will live on PyPI: https://pypi.org/project/sampleproject/
+#
+# There are some restrictions on what makes a valid project name
+# specification here:
+# https://packaging.python.org/specifications/core-metadata/#name
+name = "aprsd"
+description = "APRSd is a APRS-IS server that can be used to connect to APRS-IS and send and receive APRS packets."
+
+# Specify which Python versions you support. In contrast to the
+# 'Programming Language' classifiers in this file, 'pip install' will check this
+# and refuse to install the project if the version does not match. See
+# https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
+requires-python = ">=3.8"
+
+dynamic = ["version", "dependencies", "optional-dependencies"]
+
+# This is an optional longer description of your project that represents
+# the body of text which users will see when they visit PyPI.
+#
+# Often, this is the same as your README, so you can just read it in from
+# that file directly.
+#
+# This field corresponds to the "Description" metadata field:
+# https://packaging.python.org/specifications/core-metadata/#description-optional
+readme = {file = "README.rst", content-type = "text/x-rst"}
+
+
+# This is either text indicating the license for the distribution, or a file
+# that contains the license.
+# https://packaging.python.org/en/latest/specifications/core-metadata/#license
+license = {file = "LICENSE"}
+
+# This should be your name or the name of the organization who originally
+# authored the project, and a valid email address corresponding to the name
+# listed.
+authors = [
+    {name = "Craig Lamparter", email = "craig@craiger.org"},
+    {name = "Walter A. Boring IV", email = "waboring@hemna.com"},
+    {name = "Emre Saglam", email = "emresaglam@gmail.com"},
+    {name = "Jason Martin", email= "jhmartin@toger.us"},
+    {name = "John", email="johng42@users.noreply.github.com"},
+    {name = "Martiros Shakhzadyan", email="vrzh@vrzh.net"},
+    {name = "Zoe Moore", email="zoenb@mailbox.org"},
+    {name = "ranguli", email="hello@joshmurphy.ca"},
+]
+
+# This should be your name or the names of the organization who currently
+# maintains the project, and a valid email address corresponding to the name
+# listed.
+maintainers = [
+    {name = "Craig Lamparter", email = "craig@craiger.org"},
+    {name = "Walter A. Boring IV", email = "waboring@hemna.com"},
+]
+
+# This field adds keywords for your project which will appear on the
+# project page. What does your project relate to?
+#
+# Note that this is a list of additional keywords, separated
+# by commas, to be used to assist searching for the distribution in a
+# larger catalog.
+keywords = [
+    "aprs",
+    "aprs-is",
+    "aprsd",
+    "aprsd-server",
+    "aprsd-client",
+    "aprsd-socket",
+    "aprsd-socket-server",
+    "aprsd-socket-client",
+]
+
+# Classifiers help users find your project by categorizing it.
+#
+# For a list of valid classifiers, see https://pypi.org/classifiers/
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Environment :: Console",
+    "Intended Audience :: Developers",
+    "Intended Audience :: End Users/Desktop",
+    "Intended Audience :: Information Technology",
+    "Topic :: Communications :: Ham Radio",
+    "Topic :: Communications :: Internet Relay Chat",
+    "Topic :: Internet",
+    "Programming Language :: Python :: 3 :: Only",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+]
+
+# This field lists other packages that your project depends on to run.
+# Any package you put here will be installed by pip when your project is
+# installed, so they must be valid existing projects.
+#
+# For an analysis of this field vs pip's requirements files see:
+# https://packaging.python.org/discussions/install-requires-vs-requirements/
+[tool.setuptools.dynamic]
+dependencies = {file = ["./requirements.txt"]}
+optional-dependencies.dev = {file = ["./requirements-dev.txt"]}
+
+# List additional groups of dependencies here (e.g. development
+# dependencies). Users will be able to install these using the "extras"
+# syntax, for example:
+#
+#   $ pip install sampleproject[dev]
+#
+# Optional dependencies the project provides. These are commonly
+# referred to as "extras". For a more extensive definition see:
+# https://packaging.python.org/en/latest/specifications/dependency-specifiers/#extras
+# [project.optional-dependencies]
+
+# List URLs that are relevant to your project
+#
+# This field corresponds to the "Project-URL" and "Home-Page" metadata fields:
+# https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use
+# https://packaging.python.org/specifications/core-metadata/#home-page-optional
+#
+# Examples listed include a pattern for specifying where the package tracks
+# issues, where the source is hosted, where to say thanks to the package
+# maintainers, and where to support the project financially. The key is
+# what's used to render the link text on PyPI.
+[project.urls]
+"Homepage" = "https://github.com/craigerl/aprsd"
+"Bug Reports" = "https://github.com/craigerl/aprsd/issues"
+"Source" = "https://github.com/craigerl/aprsd"
+
+# The following would provide a command line executable called `sample`
+# which executes the function `main` from this package when invoked.
+[project.scripts]
+aprsd = "aprsd.main:main"
+
+[project.entry-points."oslo.config.opts"]
+    "aprsd.conf" = "aprsd.conf.opts:list_opts"
+
+[project.entry-points."oslo.config.opts.defaults"]
+    "aprsd.conf" = "aprsd.conf:set_lib_defaults"
+
+# If you are using a different build backend, you will need to change this.
+[tool.setuptools]
+# If there are data files included in your packages that need to be
+# installed, specify them here.
+py-modules = ["aprsd"]
+package-data = {"sample" = ["*.dat"]}
+
 [build-system]
-requires = ["setuptools>=46.0", "wheel"]
+requires = [
+    "setuptools>=69.5.0",
+    "setuptools_scm>=0",
+    "wheel",
+]
 build-backend = "setuptools.build_meta"
 
 [tool.isort]
@@ -14,3 +171,5 @@ skip_gitignore = true
 
 [tool.coverage.run]
 branch = true
+
+[tool.setuptools_scm]
diff --git a/dev-requirements.in b/requirements-dev.in
similarity index 88%
rename from dev-requirements.in
rename to requirements-dev.in
index 9134495..084b136 100644
--- a/dev-requirements.in
+++ b/requirements-dev.in
@@ -1,16 +1,20 @@
+build
+check-manifest
 flake8
+gray
 isort
 mypy
 pep8-naming
+pytest
+pytest-cov
+pip
+pip-tools
+pre-commit
 Sphinx
 tox
+wheel
+
 # Twine is used for uploading packages to pypi
 # but it induces an install of cryptography
 # This is sucky for rpi systems.
 # twine
-pre-commit
-pytest
-pytest-cov
-gray
-pip
-pip-tools
diff --git a/requirements-dev.txt b/requirements-dev.txt
new file mode 100644
index 0000000..5c6fa59
--- /dev/null
+++ b/requirements-dev.txt
@@ -0,0 +1,84 @@
+#
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
+#
+#    pip-compile --annotation-style=line requirements-dev.in
+#
+add-trailing-comma==3.1.0  # via gray
+alabaster==0.7.16         # via sphinx
+autoflake==1.5.3          # via gray
+babel==2.15.0             # via sphinx
+black==24.4.2             # via gray
+build==1.2.1              # via -r requirements-dev.in, check-manifest, pip-tools
+cachetools==5.3.3         # via tox
+certifi==2024.2.2         # via requests
+cfgv==3.4.0               # via pre-commit
+chardet==5.2.0            # via tox
+charset-normalizer==3.3.2  # via requests
+check-manifest==0.49      # via -r requirements-dev.in
+click==8.1.7              # via black, fixit, moreorless, pip-tools
+colorama==0.4.6           # via tox
+commonmark==0.9.1         # via rich
+configargparse==1.7       # via gray
+coverage[toml]==7.5.1     # via pytest-cov
+distlib==0.3.8            # via virtualenv
+docutils==0.21.2          # via sphinx
+exceptiongroup==1.2.1     # via pytest
+filelock==3.14.0          # via tox, virtualenv
+fixit==2.1.0              # via gray
+flake8==7.0.0             # via -r requirements-dev.in, pep8-naming
+gray==0.15.0              # via -r requirements-dev.in
+identify==2.5.36          # via pre-commit
+idna==3.7                 # via requests
+imagesize==1.4.1          # via sphinx
+iniconfig==2.0.0          # via pytest
+isort==5.13.2             # via -r requirements-dev.in, gray
+jinja2==3.1.4             # via sphinx
+libcst==1.3.1             # via fixit
+markupsafe==2.1.5         # via jinja2
+mccabe==0.7.0             # via flake8
+moreorless==0.4.0         # via fixit
+mypy==1.10.0              # via -r requirements-dev.in
+mypy-extensions==1.0.0    # via black, mypy
+nodeenv==1.8.0            # via pre-commit
+packaging==24.0           # via black, build, fixit, pyproject-api, pytest, sphinx, tox
+pathspec==0.12.1          # via black, trailrunner
+pep8-naming==0.13.3       # via -r requirements-dev.in
+pip-tools==7.4.1          # via -r requirements-dev.in
+platformdirs==4.2.1       # via black, tox, virtualenv
+pluggy==1.5.0             # via pytest, tox
+pre-commit==3.7.1         # via -r requirements-dev.in
+pycodestyle==2.11.1       # via flake8
+pyflakes==3.2.0           # via autoflake, flake8
+pygments==2.18.0          # via rich, sphinx
+pyproject-api==1.6.1      # via tox
+pyproject-hooks==1.1.0    # via build, pip-tools
+pytest==8.2.0             # via -r requirements-dev.in, pytest-cov
+pytest-cov==5.0.0         # via -r requirements-dev.in
+pyupgrade==3.15.2         # via gray
+pyyaml==6.0.1             # via libcst, pre-commit
+requests==2.31.0          # via sphinx
+rich==12.6.0              # via gray
+snowballstemmer==2.2.0    # via sphinx
+sphinx==7.3.7             # via -r requirements-dev.in
+sphinxcontrib-applehelp==1.0.8  # via sphinx
+sphinxcontrib-devhelp==1.0.6  # via sphinx
+sphinxcontrib-htmlhelp==2.0.5  # via sphinx
+sphinxcontrib-jsmath==1.0.1  # via sphinx
+sphinxcontrib-qthelp==1.0.7  # via sphinx
+sphinxcontrib-serializinghtml==1.1.10  # via sphinx
+tokenize-rt==5.2.0        # via add-trailing-comma, pyupgrade
+toml==0.10.2              # via autoflake
+tomli==2.0.1              # via black, build, check-manifest, coverage, fixit, mypy, pip-tools, pyproject-api, pytest, sphinx, tox
+tox==4.15.0               # via -r requirements-dev.in
+trailrunner==1.4.0        # via fixit
+typing-extensions==4.11.0  # via black, mypy
+unify==0.5                # via gray
+untokenize==0.1.1         # via unify
+urllib3==2.2.1            # via requests
+virtualenv==20.26.2       # via pre-commit, tox
+wheel==0.43.0             # via -r requirements-dev.in, pip-tools
+
+# The following packages are considered to be unsafe in a requirements file:
+# pip
+# setuptools
diff --git a/requirements.in b/requirements.in
index 05f2f75..7feaaf5 100644
--- a/requirements.in
+++ b/requirements.in
@@ -1,38 +1,32 @@
 aprslib>=0.7.0
-click
-click-params
-flask
-werkzeug
-flask-httpauth
-imapclient
-pluggy
-pbr
-pyyaml
-requests
-pytz
-tzlocal
-six
-thesmuggler
-update_checker
-flask-socketio
-python-socketio
-gevent
-eventlet
-tabulate
-# Pinned due to gray needing 12.6.0
-rich~=12.6.0
 # For the list-plugins pypi.org search scraping
 beautifulsoup4
-wrapt
-# kiss3 uses attrs
-kiss3
-attrs
+click
+click-params
 dataclasses
-oslo.config
-# Pin this here so it doesn't require a compile on
-# raspi
-shellingham
-geopy
-rush
 dataclasses-json
+eventlet
+flask
+flask-httpauth
+flask-socketio
+geopy
+gevent
+imapclient
+kiss3
 loguru
+oslo.config
+pluggy
+python-socketio
+pyyaml
+pytz
+requests
+# Pinned due to gray needing 12.6.0
+rich~=12.6.0
+rush
+shellingham
+six
+tabulate
+thesmuggler
+tzlocal
+update_checker
+wrapt
diff --git a/requirements.txt b/requirements.txt
index 47db18f..9d381a1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,183 +4,78 @@
 #
 #    pip-compile --annotation-style=line requirements.in
 #
-aprslib==0.7.2
-    # via -r requirements.in
-attrs==23.2.0
-    # via
-    #   -r requirements.in
-    #   ax253
-    #   kiss3
-    #   rush
-ax253==0.1.5.post1
-    # via kiss3
-beautifulsoup4==4.12.3
-    # via -r requirements.in
-bidict==0.23.1
-    # via python-socketio
-bitarray==2.9.2
-    # via
-    #   ax253
-    #   kiss3
-blinker==1.7.0
-    # via flask
-certifi==2024.2.2
-    # via requests
-charset-normalizer==3.3.2
-    # via requests
-click==8.1.7
-    # via
-    #   -r requirements.in
-    #   click-params
-    #   flask
-click-params==0.5.0
-    # via -r requirements.in
-commonmark==0.9.1
-    # via rich
-dataclasses==0.6
-    # via -r requirements.in
-dataclasses-json==0.6.4
-    # via -r requirements.in
-debtcollector==3.0.0
-    # via oslo-config
-deprecated==1.2.14
-    # via click-params
-dnspython==2.6.1
-    # via eventlet
-eventlet==0.36.1
-    # via -r requirements.in
-flask==3.0.3
-    # via
-    #   -r requirements.in
-    #   flask-httpauth
-    #   flask-socketio
-flask-httpauth==4.8.0
-    # via -r requirements.in
-flask-socketio==5.3.6
-    # via -r requirements.in
-geographiclib==2.0
-    # via geopy
-geopy==2.4.1
-    # via -r requirements.in
-gevent==24.2.1
-    # via -r requirements.in
-greenlet==3.0.3
-    # via
-    #   eventlet
-    #   gevent
-h11==0.14.0
-    # via wsproto
-idna==3.7
-    # via requests
-imapclient==3.0.1
-    # via -r requirements.in
-importlib-metadata==7.1.0
-    # via
-    #   ax253
-    #   kiss3
-itsdangerous==2.2.0
-    # via flask
-jinja2==3.1.4
-    # via flask
-kiss3==8.0.0
-    # via -r requirements.in
-loguru==0.7.2
-    # via -r requirements.in
-markupsafe==2.1.5
-    # via
-    #   jinja2
-    #   werkzeug
-marshmallow==3.21.1
-    # via dataclasses-json
-mypy-extensions==1.0.0
-    # via typing-inspect
-netaddr==1.2.1
-    # via oslo-config
-oslo-config==9.4.0
-    # via -r requirements.in
-oslo-i18n==6.3.0
-    # via oslo-config
-packaging==24.0
-    # via marshmallow
-pbr==6.0.0
-    # via
-    #   -r requirements.in
-    #   oslo-i18n
-    #   stevedore
-pluggy==1.5.0
-    # via -r requirements.in
-pygments==2.17.2
-    # via rich
-pyserial==3.5
-    # via pyserial-asyncio
-pyserial-asyncio==0.6
-    # via kiss3
-python-engineio==4.9.0
-    # via python-socketio
-python-socketio==5.11.2
-    # via
-    #   -r requirements.in
-    #   flask-socketio
-pytz==2024.1
-    # via -r requirements.in
-pyyaml==6.0.1
-    # via
-    #   -r requirements.in
-    #   oslo-config
-requests==2.31.0
-    # via
-    #   -r requirements.in
-    #   oslo-config
-    #   update-checker
-rfc3986==2.0.0
-    # via oslo-config
-rich==12.6.0
-    # via -r requirements.in
-rush==2021.4.0
-    # via -r requirements.in
-shellingham==1.5.4
-    # via -r requirements.in
-simple-websocket==1.0.0
-    # via python-engineio
-six==1.16.0
-    # via -r requirements.in
-soupsieve==2.5
-    # via beautifulsoup4
-stevedore==5.2.0
-    # via oslo-config
-tabulate==0.9.0
-    # via -r requirements.in
-thesmuggler==1.0.1
-    # via -r requirements.in
-typing-extensions==4.11.0
-    # via typing-inspect
-typing-inspect==0.9.0
-    # via dataclasses-json
-tzlocal==5.2
-    # via -r requirements.in
-update-checker==0.18.0
-    # via -r requirements.in
-urllib3==2.2.1
-    # via requests
-validators==0.22.0
-    # via click-params
-werkzeug==3.0.2
-    # via
-    #   -r requirements.in
-    #   flask
-wrapt==1.16.0
-    # via
-    #   -r requirements.in
-    #   debtcollector
-    #   deprecated
-wsproto==1.2.0
-    # via simple-websocket
-zipp==3.18.1
-    # via importlib-metadata
-zope-event==5.0
-    # via gevent
-zope-interface==6.3
-    # via gevent
+aprslib==0.7.2            # via -r requirements.in
+attrs==23.2.0             # via ax253, kiss3, rush
+ax253==0.1.5.post1        # via kiss3
+beautifulsoup4==4.12.3    # via -r requirements.in
+bidict==0.23.1            # via python-socketio
+bitarray==2.9.2           # via ax253, kiss3
+blinker==1.8.2            # via flask
+certifi==2024.2.2         # via requests
+charset-normalizer==3.3.2  # via requests
+click==8.1.7              # via -r requirements.in, click-params, flask
+click-params==0.5.0       # via -r requirements.in
+commonmark==0.9.1         # via rich
+dataclasses==0.6          # via -r requirements.in
+dataclasses-json==0.6.6   # via -r requirements.in
+debtcollector==3.0.0      # via oslo-config
+deprecated==1.2.14        # via click-params
+dnspython==2.6.1          # via eventlet
+eventlet==0.36.1          # via -r requirements.in
+flask==3.0.3              # via -r requirements.in, flask-httpauth, flask-socketio
+flask-httpauth==4.8.0     # via -r requirements.in
+flask-socketio==5.3.6     # via -r requirements.in
+geographiclib==2.0        # via geopy
+geopy==2.4.1              # via -r requirements.in
+gevent==24.2.1            # via -r requirements.in
+greenlet==3.0.3           # via eventlet, gevent
+h11==0.14.0               # via wsproto
+idna==3.7                 # via requests
+imapclient==3.0.1         # via -r requirements.in
+importlib-metadata==7.1.0  # via ax253, kiss3
+itsdangerous==2.2.0       # via flask
+jinja2==3.1.4             # via flask
+kiss3==8.0.0              # via -r requirements.in
+loguru==0.7.2             # via -r requirements.in
+markupsafe==2.1.5         # via jinja2, werkzeug
+marshmallow==3.21.2       # via dataclasses-json
+mypy-extensions==1.0.0    # via typing-inspect
+netaddr==1.2.1            # via oslo-config
+oslo-config==9.4.0        # via -r requirements.in
+oslo-i18n==6.3.0          # via oslo-config
+packaging==24.0           # via marshmallow
+pbr==6.0.0                # via oslo-i18n, stevedore
+pluggy==1.5.0             # via -r requirements.in
+pygments==2.18.0          # via rich
+pyserial==3.5             # via pyserial-asyncio
+pyserial-asyncio==0.6     # via kiss3
+python-engineio==4.9.0    # via python-socketio
+python-socketio==5.11.2   # via -r requirements.in, flask-socketio
+pytz==2024.1              # via -r requirements.in
+pyyaml==6.0.1             # via -r requirements.in, oslo-config
+requests==2.31.0          # via -r requirements.in, oslo-config, update-checker
+rfc3986==2.0.0            # via oslo-config
+rich==12.6.0              # via -r requirements.in
+rush==2021.4.0            # via -r requirements.in
+shellingham==1.5.4        # via -r requirements.in
+simple-websocket==1.0.0   # via python-engineio
+six==1.16.0               # via -r requirements.in
+soupsieve==2.5            # via beautifulsoup4
+stevedore==5.2.0          # via oslo-config
+tabulate==0.9.0           # via -r requirements.in
+thesmuggler==1.0.1        # via -r requirements.in
+typing-extensions==4.11.0  # via typing-inspect
+typing-inspect==0.9.0     # via dataclasses-json
+tzlocal==5.2              # via -r requirements.in
+update-checker==0.18.0    # via -r requirements.in
+urllib3==2.2.1            # via requests
+validators==0.22.0        # via click-params
+werkzeug==3.0.3           # via flask
+wrapt==1.16.0             # via -r requirements.in, debtcollector, deprecated
+wsproto==1.2.0            # via simple-websocket
+zipp==3.18.1              # via importlib-metadata
+zope-event==5.0           # via gevent
+zope-interface==6.3       # via gevent
 
 # The following packages are considered to be unsafe in a requirements file:
 # setuptools
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index ac77dc6..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,51 +0,0 @@
-[metadata]
-name = aprsd
-long_description = file: README.rst
-long_description_content_type = text/x-rst
-url = http://aprsd.readthedocs.org
-author = Craig Lamparter
-author_email = something@somewhere.com
-license = Apache
-license_file = LICENSE
-classifier =
-    License :: OSI Approved :: Apache Software License
-    Topic :: Communications :: Ham Radio
-    Operating System :: POSIX :: Linux
-    Programming Language :: Python :: 3 :: Only
-    Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.7
-    Programming Language :: Python :: 3.8
-    Programming Language :: Python :: 3.9
-description_file =
-    README.rst
-project_urls =
-    Source=https://github.com/craigerl/aprsd
-    Tracker=https://github.com/craigerl/aprsd/issues
-summary = Amateur radio APRS daemon which listens for messages and responds
-
-[global]
-setup-hooks =
-    pbr.hooks.setup_hook
-
-[files]
-packages =
-    aprsd
-
-[entry_points]
-console_scripts =
-    aprsd = aprsd.main:main
-oslo.config.opts =
-    aprsd.conf = aprsd.conf.opts:list_opts
-oslo.config.opts.defaults =
-    aprsd.conf = aprsd.conf:set_lib_defaults
-
-[build_sphinx]
-source-dir = docs
-build-dir = docs/_build
-all_files = 1
-
-[upload_sphinx]
-upload-dir = docs/_build
-
-[bdist_wheel]
-universal = 1
diff --git a/setup.py b/setup.py
index 042f113..aec584f 100644
--- a/setup.py
+++ b/setup.py
@@ -17,12 +17,4 @@
 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
-try:
-    import multiprocessing  # noqa
-except ImportError:
-    pass
-
-setuptools.setup(setup_requires=["pbr"], pbr=True)
+setuptools.setup()
diff --git a/tox.ini b/tox.ini
index eed3e9d..564711e 100644
--- a/tox.ini
+++ b/tox.ini
@@ -23,7 +23,7 @@ install_command = pip install {opts} {packages}
 extras = tests
 deps = coverage: coverage
        -r{toxinidir}/requirements.txt
-       -r{toxinidir}/dev-requirements.txt
+       -r{toxinidir}/requirements-dev.txt
        pytestmain: git+https://github.com/pytest-dev/pytest.git@main
 commands =
     pytest -v --cov-report term-missing --cov=aprsd {posargs}
@@ -34,7 +34,7 @@ commands =
 skip_install = true
 deps =
     -r{toxinidir}/requirements.txt
-    -r{toxinidir}/dev-requirements.txt
+    -r{toxinidir}/requirements-dev.txt
     {toxinidir}/.
 changedir = {toxinidir}/docs
 commands =
@@ -57,7 +57,7 @@ passenv = FAST8_NUM_COMMITS
 [testenv:lint]
 skip_install = true
 deps =
-    -r{toxinidir}/dev-requirements.txt
+    -r{toxinidir}/requirements-dev.txt
 commands =
     flake8 aprsd tests
 
@@ -85,14 +85,14 @@ python =
 # and standard formatting
 skip_install = true
 deps =
-    -r{toxinidir}/dev-requirements.txt
+    -r{toxinidir}/requirements-dev.txt
 commands =
     gray aprsd tests
 
 [testenv:type-check]
 skip_install = true
 deps = -r{toxinidir}/requirements.txt
-    -r{toxinidir}/dev-requirements.txt
+    -r{toxinidir}/requirements-dev.txt
 commands =
     mypy --ignore-missing-imports --install-types aprsd