From 414ff31fd0ed108398d6d70e94f5cbbf42b2e788 Mon Sep 17 00:00:00 2001 From: Walter Boring Date: Fri, 16 Jan 2026 12:17:21 -0500 Subject: [PATCH] switch to pyproject.toml and update tox.ini --- .pre-commit-config.yaml | 20 ++++--- AUTHORS | 1 + ChangeLog | 10 ++++ aprsd_twitter_plugin/__init__.py | 1 - aprsd_twitter_plugin/conf/__init__.py | 1 - aprsd_twitter_plugin/conf/opts.py | 8 +-- aprsd_twitter_plugin/conf/twitter.py | 25 +++++---- aprsd_twitter_plugin/twitter.py | 43 +++++++-------- pyproject.toml | 76 +++++++++++++++++++++++++++ requirements-dev.txt | 12 ----- requirements.txt | 4 -- setup.py | 12 +---- tox.ini | 54 ++++++++++--------- 13 files changed, 169 insertions(+), 98 deletions(-) create mode 100644 pyproject.toml delete mode 100644 requirements-dev.txt delete mode 100644 requirements.txt diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f73a842..0392d5f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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] diff --git a/AUTHORS b/AUTHORS index cc71ac7..3a44899 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,2 @@ Hemna +Walter A. Boring IV diff --git a/ChangeLog b/ChangeLog index 6d806e0..3e514b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 ------ diff --git a/aprsd_twitter_plugin/__init__.py b/aprsd_twitter_plugin/__init__.py index 62da5ff..63f1e41 100644 --- a/aprsd_twitter_plugin/__init__.py +++ b/aprsd_twitter_plugin/__init__.py @@ -12,5 +12,4 @@ import pbr.version - __version__ = pbr.version.VersionInfo("aprsd_twitter_plugin").version_string() diff --git a/aprsd_twitter_plugin/conf/__init__.py b/aprsd_twitter_plugin/conf/__init__.py index a8ddbfe..1380c24 100644 --- a/aprsd_twitter_plugin/conf/__init__.py +++ b/aprsd_twitter_plugin/conf/__init__.py @@ -2,6 +2,5 @@ from oslo_config import cfg from aprsd_twitter_plugin.conf import twitter - CONF = cfg.CONF twitter.register_opts(CONF) diff --git a/aprsd_twitter_plugin/conf/opts.py b/aprsd_twitter_plugin/conf/opts.py index d411b5e..3822238 100644 --- a/aprsd_twitter_plugin/conf/opts.py +++ b/aprsd_twitter_plugin/conf/opts.py @@ -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) diff --git a/aprsd_twitter_plugin/conf/twitter.py b/aprsd_twitter_plugin/conf/twitter.py index 66800ba..0fd1407 100644 --- a/aprsd_twitter_plugin/conf/twitter.py +++ b/aprsd_twitter_plugin/conf/twitter.py @@ -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): diff --git a/aprsd_twitter_plugin/twitter.py b/aprsd_twitter_plugin/twitter.py index 1d25e25..dbdf41d 100644 --- a/aprsd_twitter_plugin/twitter.py +++ b/aprsd_twitter_plugin/twitter.py @@ -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) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..153fc7d --- /dev/null +++ b/pyproject.toml @@ -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" diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 7555017..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,12 +0,0 @@ -pip -pip-tools -bump2version -wheel -watchdog -flake8 -tox -coverage -Sphinx -twine -pytest==6.2.5 -gray diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 78c0d92..0000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -pbr -aprsd>=3.0.0 -tweepy -oslo.config diff --git a/setup.py b/setup.py index b0b7861..e903d2e 100644 --- a/setup.py +++ b/setup.py @@ -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() diff --git a/tox.ini b/tox.ini index 3d3947e..862017f 100644 --- a/tox.ini +++ b/tox.ini @@ -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}