switch to pyproject.toml and update tox.ini

This commit is contained in:
Walter Boring 2026-01-16 12:17:21 -05:00
parent 6eadbd0555
commit 414ff31fd0
13 changed files with 169 additions and 98 deletions

View File

@ -1,23 +1,29 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-json
- id: detect-private-key
- id: check-merge-conflict
- id: check-case-conflict
- id: check-docstring-first
- id: check-builtin-literals
- id: check-illegal-windows-names
- repo: https://github.com/asottile/setup-cfg-fmt
rev: v1.16.0
rev: v2.7.0
hooks:
- id: setup-cfg-fmt
- repo: https://github.com/dizballanze/gray
rev: v0.10.1
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.10
hooks:
- id: gray
###### Relevant part below ######
- id: ruff-check
types_or: [python, pyi]
args: ["check", "--select", "I", "--fix"]
###### Relevant part above ######
- id: ruff-format
types_or: [python, pyi]

View File

@ -1 +1,2 @@
Hemna <waboring@hemna.com>
Walter A. Boring IV <waboring@hemna.com>

View File

@ -1,6 +1,16 @@
CHANGES
=======
v0.5.0
------
* fixed pep8 error
* fixed requirements.txt
* Update for aprsd 3.0.0
* Update for aprsd 2.7.0
* remove trace
* Create FUNDING.yml
v0.3.0
------

View File

@ -12,5 +12,4 @@
import pbr.version
__version__ = pbr.version.VersionInfo("aprsd_twitter_plugin").version_string()

View File

@ -2,6 +2,5 @@ from oslo_config import cfg
from aprsd_twitter_plugin.conf import twitter
CONF = cfg.CONF
twitter.register_opts(CONF)

View File

@ -31,7 +31,6 @@ import importlib
import os
import pkgutil
LIST_OPTS_FUNC_NAME = "list_opts"
@ -64,9 +63,10 @@ def _import_modules(module_names):
for modname in module_names:
mod = importlib.import_module("aprsd_twitter_plugin.conf." + modname)
if not hasattr(mod, LIST_OPTS_FUNC_NAME):
msg = "The module 'aprsd_twitter_plugin.conf.%s' should have a '%s' "\
"function which returns the config options." % \
(modname, LIST_OPTS_FUNC_NAME)
msg = (
f"The module 'aprsd_twitter_plugin.conf.{modname}' should have a "
f"'{LIST_OPTS_FUNC_NAME}' function which returns the config options."
)
raise Exception(msg)
else:
imported_modules.append(mod)

View File

@ -1,6 +1,5 @@
from oslo_config import cfg
twitter_group = cfg.OptGroup(
name="aprsd_twitter_plugin",
title="APRSD Twitter Plugin settings",
@ -10,17 +9,23 @@ twitter_opts = [
cfg.StrOpt(
"callsign",
help="Callsign allowed to send tweets! "
"Any callsign starting with this will be allowed to tweet to"
"the configured twitter account. "
"For example, if you set this to WB4BOR then any"
"callsign starting with WB4BOR will be allowed to tweet."
"This way WB4BOR-1 can tweet from this instance.",
"Any callsign starting with this will be allowed to tweet to"
"the configured twitter account. "
"For example, if you set this to WB4BOR then any"
"callsign starting with WB4BOR will be allowed to tweet."
"This way WB4BOR-1 can tweet from this instance.",
),
cfg.StrOpt(
"bearer_token",
help="Your twitter Bearer Token"
"Information for creating your api keys is here: "
"https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code",
),
cfg.StrOpt(
"apiKey",
help="Your twitter apiKey"
"Information for creating your api keys is here: "
"https://developer.twitter.com/en/docs/authentication/oauth-1-0a/api-key-and-secret",
"Information for creating your api keys is here: "
"https://developer.twitter.com/en/docs/authentication/oauth-1-0a/api-key-and-secret",
),
cfg.StrOpt(
"apiKey_secret",
@ -41,9 +46,7 @@ twitter_opts = [
),
]
ALL_OPTS = (
twitter_opts
)
ALL_OPTS = twitter_opts
def register_opts(cfg):

View File

@ -1,20 +1,20 @@
import logging
import tweepy
from aprsd import conf # noqa
from aprsd import plugin
from aprsd import (
conf, # noqa
plugin,
)
from oslo_config import cfg
import aprsd_twitter_plugin
from aprsd_twitter_plugin import conf # noqa
from aprsd_twitter_plugin import conf as twitter_conf # noqa
CONF = cfg.CONF
LOG = logging.getLogger("APRSD")
class SendTweetPlugin(plugin.APRSDRegexCommandPluginBase):
version = aprsd_twitter_plugin.__version__
# Look for any command that starts with tw or tW or TW or Tw
# or case insensitive version of 'twitter'
@ -37,37 +37,32 @@ class SendTweetPlugin(plugin.APRSDRegexCommandPluginBase):
if not CONF.aprsd_twitter_plugin.callsign:
LOG.error(
"No aprsd_twitter_pligin.callsign is set."
" Callsign is needed to allow tweets!",
"No aprsd_twitter_pligin.callsign is set. Callsign is needed to allow tweets!",
)
self.enabled = False
# Ensure the access token exists.
if not CONF.aprsd_twitter_plugin.apiKey:
LOG.error(
"No aprsd_twitter_plugin.apiKey is set!."
" Plugin Disabled.",
"No aprsd_twitter_plugin.apiKey is set!. Plugin Disabled.",
)
self.enabled = False
if not CONF.aprsd_twitter_plugin.apiKey_secret:
LOG.error(
"No aprsd_twitter_plugin.apiKey_secret is set."
" Plugin Disabled.",
"No aprsd_twitter_plugin.apiKey_secret is set. Plugin Disabled.",
)
self.enabled = False
if not CONF.aprsd_twitter_plugin.access_token:
LOG.error(
"No aprsd_twitter_plugin.access_token exists."
" Plugin Disabled.",
"No aprsd_twitter_plugin.access_token exists. Plugin Disabled.",
)
self.enabled = False
if not CONF.aprsd_twitter_plugin.access_token_secret:
LOG.error(
"No aprsd_twitter_plugin.access_token_secret exists."
" Plugin Disabled.",
"No aprsd_twitter_plugin.access_token_secret exists. Plugin Disabled.",
)
self.enabled = False
@ -83,11 +78,21 @@ class SendTweetPlugin(plugin.APRSDRegexCommandPluginBase):
CONF.aprsd_twitter_plugin.access_token_secret,
)
bearer_token = CONF.aprsd_twitter_plugin.bearer_token
api = tweepy.API(
auth,
bearer_token,
wait_on_rate_limit=True,
)
tweepy.OAuth2UserHandler(
client_id="Client ID here",
redirect_uri="Callback / Redirect URI / URL here",
scope=["tweet.write"],
# Client Secret is only necessary if using a confidential client
client_secret="Client Secret here",
)
try:
api.verify_credentials()
LOG.debug("Logged in to Twitter Authentication OK")
@ -99,7 +104,6 @@ class SendTweetPlugin(plugin.APRSDRegexCommandPluginBase):
return api
def process(self, packet):
"""This is called when a received packet matches self.command_regex."""
LOG.info("SendTweetPlugin Plugin")
@ -123,10 +127,7 @@ class SendTweetPlugin(plugin.APRSDRegexCommandPluginBase):
return "Failed to Auth"
if CONF.aprsd_twitter_plugin.add_aprs_hashtag:
message += (
" #aprs #aprsd #hamradio "
"https://github.com/hemna/aprsd-twitter-plugin"
)
message += " #aprs #aprsd #hamradio https://github.com/hemna/aprsd-twitter-plugin"
# Now lets tweet!
client.update_status(message)

76
pyproject.toml Normal file
View File

@ -0,0 +1,76 @@
[build-system]
requires = ["setuptools>=61.0", "wheel", "pbr"]
build-backend = "setuptools.build_meta"
[project]
name = "aprsd_twitter_plugin"
version = "0.0.0" # Version managed by pbr
description = "Python APRSD plugin to send tweets"
readme = "README.rst"
requires-python = ">=3.11"
license = {text = "MIT"}
authors = [
{name = "Walter A. Boring IV", email = "waboring@hemna.com"}
]
classifiers = [
"License :: OSI Approved :: MIT License",
"Topic :: Communications :: Ham Radio",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python",
"Programming Language :: Python :: 3.11",
]
dependencies = [
"pbr",
"aprsd>=3.0.0",
"tweepy",
"oslo.config",
]
[project.optional-dependencies]
dev = [
"pip",
"pip-tools",
"bump2version",
"wheel",
"watchdog",
"ruff",
"tox",
"tox-uv",
"coverage",
"Sphinx",
"twine",
"pytest",
"gray",
]
[tool.setuptools]
packages = ["aprsd_twitter_plugin"]
[tool.setuptools.package-data]
"*" = ["LICENSE"]
[project.entry-points."oslo.config.opts"]
"aprsd_twitter_plugin.conf" = "aprsd_twitter_plugin.conf.opts:list_opts" # type: ignore
[project.entry-points."oslo.config.opts.defaults"]
"aprsd_twitter_plugin.conf" = "aprsd_twitter_plugin.conf.opts:defaults" # type: ignore
[tool.pbr]
# PBR configuration
[tool.mypy]
ignore_missing_imports = true
strict = true
[tool.ruff]
line-length = 99
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "UP"]
ignore = ["E203"]
exclude = ["venv", ".venv", "__pycache__", "build", "dist"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"

View File

@ -1,12 +0,0 @@
pip
pip-tools
bump2version
wheel
watchdog
flake8
tox
coverage
Sphinx
twine
pytest==6.2.5
gray

View File

@ -1,4 +0,0 @@
pbr
aprsd>=3.0.0
tweepy
oslo.config

View File

@ -1,4 +1,3 @@
#
# 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
@ -15,13 +14,4 @@
# 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
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup(setup_requires=["pbr"], pbr=True)
setuptools.setup()

54
tox.ini
View File

@ -4,26 +4,17 @@
envlist =
fmt
lint
py{37,38,39}
py311
skip_missing_interpreters = true
[flake8]
# Use the more relaxed max line length permitted in PEP8.
max-line-length = 99
# This ignore is required by black.
extend-ignore = E203
extend-exclude =
venv
requires =
tox-uv>=0.1.0
# This is the configuration for the tox-gh-actions plugin for GitHub Actions
# https://github.com/ymyzk/tox-gh-actions
# This section is not needed if not using GitHub Actions for CI.
[gh-actions]
python =
3.7: py37
3.8: py38, fmt, lint
3.9: py39
3.11: py311, fmt, lint
# Activate isolated build environment. tox will use a virtual environment
@ -31,35 +22,38 @@ python =
# arguments use the pyproject.toml file as specified in PEP-517 and PEP-518.
isolated_build = true
[testenv]
[testenv:base]
package = editable
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements-dev.txt
pytest
[testenv]
package = editable
deps =
{[testenv:base]deps}
commands =
# Use -bb to enable BytesWarnings as error to catch str/bytes misuse.
# Use -Werror to treat warnings as errors.
{envpython} -bb -Werror -m pytest {posargs}
uv run pytest tests {posargs}
[testenv:type-check]
skip_install = true
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements-dev.txt
mypy
commands =
mypy src tests
[testenv:lint]
skip_install = true
deps =
-r{toxinidir}/requirements-dev.txt
ruff
commands =
flake8 aprsd_twitter_plugin tests
ruff check aprsd_twitter_plugin tests
[testenv:docs]
skip_install = true
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/requirements-dev.txt
Sphinx
changedir = {toxinidir}/docs
commands =
{envpython} clean_docs.py
@ -69,15 +63,23 @@ commands =
[testenv:fmt]
skip_install = true
deps =
-r{toxinidir}/requirements-dev.txt
ruff
commands =
gray aprsd_twitter_plugin tests
ruff format aprsd_twitter_plugin tests
ruff check --fix aprsd_twitter_plugin tests
[testenv:fmt-fix]
skip_install = true
deps =
ruff
commands =
ruff format aprsd_twitter_plugin tests
ruff check --fix aprsd_twitter_plugin tests
[testenv:licenses]
skip_install = true
recreate = true
deps =
-r{toxinidir}/requirements.txt
pip-licenses
commands =
pip-licenses {posargs}