From 3761316d0580a2ca0bac68dc5696cef79543aa45 Mon Sep 17 00:00:00 2001 From: James Bennett Date: Sun, 10 Nov 2024 00:50:36 -0800 Subject: [PATCH] Prep for 24.11.0. --- .github/workflows/ci.yml | 17 +-- .gitignore | 3 + .pre-commit-config.yaml | 6 +- CONTRIBUTING.rst | 82 ++++++++---- MANIFEST.in | 14 --- docs/changelog.rst | 8 ++ docs/faq.rst | 5 +- docs/install.rst | 28 ++--- docs/requirements.txt | 13 ++ docs/testing.rst | 10 +- noxfile.py | 75 ++++++----- pdm.lock | 262 +++++++++++++++++++++++++++++++++++++++ pyproject.toml | 62 ++++----- src/akismet/__init__.py | 3 - src/akismet/_common.py | 4 +- src/akismet/_version.py | 12 -- tox.ini | 188 ---------------------------- 17 files changed, 442 insertions(+), 350 deletions(-) delete mode 100644 MANIFEST.in create mode 100644 docs/requirements.txt create mode 100644 pdm.lock delete mode 100644 src/akismet/_version.py delete mode 100644 tox.ini diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cef2e96..14315e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ name: CI on: push: - branches: [trunk] + branches: [ trunk ] pull_request: workflow_dispatch: @@ -12,7 +12,7 @@ env: PIP_DISABLE_PIP_VERSION_CHECK: "1" PIP_NO_PYTHON_VERSION_WARNING: "1" -permissions: {} +permissions: { } jobs: build-package: @@ -23,6 +23,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + persist-credentials: false - uses: hynek/build-and-inspect-python-package@v2 id: baipp @@ -74,6 +75,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - uses: actions/setup-python@v5 with: python-version: "3.12" @@ -140,7 +143,7 @@ jobs: - run: tar xf dist/*.tar.gz --strip-components=1 - uses: actions/setup-python@v5 with: - python-version: "3.12" + python-version: "3.13" - name: Set up test runner run: | python -VV @@ -148,9 +151,9 @@ jobs: python -Im pip install --upgrade nox python -Im nox --version - name: Check code formatting - run: "python -Im nox --non-interactive --error-on-external-run --tag formatters --python 3.12" + run: "python -Im nox --non-interactive --error-on-external-run --tag formatters --python 3.13" - name: Lint code - run: "python -Im nox --non-interactive --error-on-external-run --tag linters --python 3.12" + run: "python -Im nox --non-interactive --error-on-external-run --tag linters --python 3.13" check-package: @@ -166,7 +169,7 @@ jobs: - run: tar xf dist/*.tar.gz --strip-components=1 - uses: actions/setup-python@v5 with: - python-version: "3.12" + python-version: "3.13" - name: Set up test runner run: | python -VV @@ -174,7 +177,7 @@ jobs: python -Im pip install --upgrade nox python -Im nox --version - name: Check package - run: "python -Im nox --non-interactive --error-on-external-run --tag packaging --python 3.12" + run: "python -Im nox --non-interactive --error-on-external-run --tag packaging --python 3.13" required-checks-pass: diff --git a/.gitignore b/.gitignore index f8a9b81..f90904f 100644 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,6 @@ cython_debug/ # IDEs .idea/ .vscode/ + +# PDM local file. +.pdm-python diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ee9101f..80d0fc9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-added-large-files - id: check-ast @@ -16,10 +16,10 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 24.8.0 + rev: 24.10.0 hooks: - id: black - language_version: python3.8 + language_version: python3.13 name: black (Python formatter) - repo: https://github.com/pycqa/flake8 rev: 7.1.1 diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 35c6fde..a31817b 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -6,8 +6,8 @@ have been set up to make the process easier for everyone (including you!). -Dev environment recommendations -------------------------------- +Prerequisites +------------- * Please use a code editor/IDE that supports `EditorConfig `_. Most editors do nowadays, so you @@ -18,17 +18,53 @@ Dev environment recommendations installed, and in your local checkout of this repository run ``pre-commit install`` to set up the pre-commit hooks. -* Please have `nox `_ installed on - your computer, and run at least the unit-test suite (``python -m nox - --tag tests``) before you push your commits to GitHub. If you can - manage it, installing the full set of supported Python versions and - running the entire suite (``python -m nox``) is even better. Tools - like `pyenv `_ or ``asdf - `_ can help with installing and managing - multiple Python versions. +The following two tools are *required* for working with this +repository: -Following these steps will catch a lot of potential problems for you, -and can even fix several of them automatically. +* `PDM `_ + +* `nox `_ + +You will also need at least one supported Python version. It is also +recommended that you test against *all* the supported Python verisions +before opening a pull request; you can use `PDM's Python installer +`_ +to install any versions of Python you need. + + +Local setup +----------- + +Once you have the tools above installed, run the following in the root +of your git checkout:: + + pdm install + +This will create a local virtual environment and install +``akismet`` and its dependencies. + + +Testing +------- + +To run the tests, use ``nox``:: + + nox --tags tests + +By default this will run against as many supported Python versions as +you have installed. To select a single specific Python version, you +can run:: + + nox --tags tests --python "3.11" + +You can also run the full CI suite locally by just invoking +``nox``. This will run the tests, check the documentation, lint the +code and check formatting, and build a package and perform checks on +it. + +For more information about available tasks, run ``nox --list`` or read +the file ``noxfile.py`` in the root of your source checkout, or the +testing documentation in the file ``docs/testing.rst``. Code style @@ -36,25 +72,23 @@ Code style The pre-commit hooks will auto-format code with `isort `_ and `Black -`_. Most editors and IDEs also support +`_. Many editors and IDEs also support auto-formatting with these tools every time you save a file. The CI suite will disallow any code that does not follow the isort/Black format. -All code must also be compatible with all versions of Python currently -supported by the Python core team. See `the Python dev guide -`_ for a current chart of -supported versions. +All code must also be compatible with all supported versions of +Python. Other guidelines ---------------- * If you need to add a new file of code, please make sure to put a - license identifier comment on the first line after the file's - docstring. You can copy and paste the license identifier comment - from any existing file, where it looks like this: ``# - SPDX-License-Identifier: BSD-3-Clause`` + license identifier comment near the top of the file. You can copy + and paste the license identifier comment from any existing file, + where it looks like this: + ``# SPDX-License-Identifier: BSD-3-Clause`` * Documentation and tests are not just recommended -- they're required. Any new file, class, method or function must have a @@ -67,9 +101,3 @@ Other guidelines docstring, or if there are any misspelled words in the documentation (and if there's a word the spell-checker should learn to recognize, add it to ``docs/spelling_wordlist.txt``). - -* Other than the tests in the special ``tests/end_to_end.py`` file, - tests for this module must not make real requests to the Akismet web - service and must not require a valid Akismet API key -- see the - existing test files for examples of how to write tests that use mock - responses. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index cbc952a..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,14 +0,0 @@ -include LICENSE -include MANIFEST.in -include .editorconfig -include *.yaml -include *.rst -include docs/*.rst docs/*.txt docs/*.py docs/*.bat docs/Makefile -include .flake8 -include pyproject.toml -include noxfile.py -include tox.ini -graft src -graft tests -global-exclude *.pyc -prune docs/_build diff --git a/docs/changelog.rst b/docs/changelog.rst index 6c41e87..4c64fbd 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -56,6 +56,14 @@ The API stability/deprecation policy for this library is as follows: Releases under CalVer --------------------- +Version 24.11.0 +~~~~~~~~~~~~~~~ + +*Under development* + +* Supported Python versions are now Python 3.9, 3.10, 3.11, 3.12, and 3.13. + + Version 24.5.1 ~~~~~~~~~~~~~~ diff --git a/docs/faq.rst b/docs/faq.rst index 0ee5832..ca03c76 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -12,9 +12,6 @@ What versions of Python are supported? The |release| release of ``akismet`` supports the following versions of Python: - -* Python 3.8 - * Python 3.9 * Python 3.10 @@ -23,6 +20,8 @@ The |release| release of ``akismet`` supports the following versions of Python: * Python 3.12 +* Python 3.13 + Older versions of Python are not supported and will cause errors. diff --git a/docs/install.rst b/docs/install.rst index 74ac399..6528ab0 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -7,8 +7,6 @@ Installation guide The |release| version of ``akismet`` is officially tested and supported on the following versions of Python: -* Python 3.8 - * Python 3.9 * Python 3.10 @@ -17,6 +15,8 @@ on the following versions of Python: * Python 3.12 +* Python 3.13 + Installing ``akismet`` ---------------------- @@ -74,10 +74,11 @@ default to ``1.0`` (one second). .. _source-install: -Installing from a source checkout ---------------------------------- +Installing for local development +-------------------------------- -If you want to work on ``akismet``, you can obtain a source checkout. +If you want to work on ``akismet``, you can obtain a source +checkout. The development repository for ``akismet`` is at . If you have `git @@ -86,18 +87,5 @@ typing:: git clone https://github.com/ubernostrum/akismet.git -From there, you can use git commands to check out the specific revision you -want, and perform an "editable" install (allowing you to change code as you -work on it) by typing: - -.. tab:: macOS/Linux/other Unix - - .. code-block:: shell - - python -m pip install -e . - -.. tab:: Windows - - .. code-block:: shell - - py -m pip install -e . +Then follow the instructions in the file ``CONTRIBUTING.rst`` in the root +directory of the source checkout. diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..220d244 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,13 @@ +# These dependencies are not "extras" defined in the pyproject.toml, +# because they're not something you actually want to install alongside +# the main package. They're also not "dev dependencies" in the PDM +# sense of the term, because PDM would constrain them to the oldest +# Python version the main package supports (3.9), while all our +# documentation jobs, whether run via nox or via readthedocs, run on +# Python 3.12. +furo +sphinx +sphinx-copybutton +sphinx-inline-tabs +sphinx-notfound-page +sphinxext-opengraph diff --git a/docs/testing.rst b/docs/testing.rst index 39ff86f..713341e 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -151,8 +151,7 @@ Running this library's tests A standard install of ``akismet`` does not install the test suite; you will need to perform :ref:`a source checkout as described in the installation guide -`, though performing the "editable" install step is not -necessary for running the tests. +`. ``akismet``'s testing tasks are run using `nox `_, so you will also need to install it, after which you can run ``nox``, which should @@ -190,11 +189,8 @@ example, to run tasks for Python 3.10 only, you could run: py -m nox --python "3.10" By default, ``nox`` will only run the tasks whose associated Python versions -are available on your system. For example, if you have only Python 3.8 and 3.9 -installed, test runs for Python 3.10, 3.11, and 3.12 would be skipped. To -install and manage multiple versions of Python, tools like `pyenv -`_ or `asdf `_ are -recommended. +are available on your system. For example, if you have only Python 3.9 and 3.13 +installed, test runs for Python 3.10, 3.11, and 3.12 would be skipped. To see a list of all available test tasks, run: diff --git a/noxfile.py b/noxfile.py index b1dbb92..ec37516 100644 --- a/noxfile.py +++ b/noxfile.py @@ -41,7 +41,7 @@ TEST_URL = "http://example.com" -def clean(paths: typing.Iterable[os.PathLike] = ARTIFACT_PATHS) -> None: +def clean(paths: typing.Iterable[pathlib.Path] = ARTIFACT_PATHS) -> None: """ Clean up after a test run. @@ -61,13 +61,17 @@ def clean(paths: typing.Iterable[os.PathLike] = ARTIFACT_PATHS) -> None: # ----------------------------------------------------------------------------------- -@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12"], tags=["tests"]) +@nox.session(python=["3.9", "3.10", "3.11", "3.12", "3.13"], tags=["tests"]) def tests_with_coverage(session: nox.Session) -> None: """ Run the package's unit tests, with coverage instrumentation. """ - session.install(".[tests]") + session.install( + ".[tests]", + "coverage", + 'tomli; python_full_version < "3.11.0a7"', + ) session.run( f"python{session.python}", "-Wonce::DeprecationWarning", @@ -84,7 +88,7 @@ def tests_with_coverage(session: nox.Session) -> None: clean() -@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12"], tags=["release"]) +@nox.session(python=["3.9", "3.10", "3.11", "3.12", "3.13"], tags=["release"]) def tests_end_to_end(session: nox.Session) -> None: """ Run the end-to-end (live Akismet API) tests. @@ -109,7 +113,7 @@ def tests_end_to_end(session: nox.Session) -> None: clean() -@nox.session(python=["3.12"], tags=["tests"]) +@nox.session(python=["3.13"], tags=["tests"]) def coverage_report(session: nox.Session) -> None: """ Combine coverage from the various test runs and output the report. @@ -133,24 +137,31 @@ def coverage_report(session: nox.Session) -> None: # ----------------------------------------------------------------------------------- +# The documentation jobs ordinarily would want to use the latest Python version, but +# currently that's 3.13 and Read The Docs doesn't yet support it. So to ensure the +# documentation jobs are as closely matched to what would happen on RTD, these jobs stay +# on 3.12 for now. @nox.session(python=["3.12"], tags=["docs"]) def docs_build(session: nox.Session) -> None: """ Build the package's documentation as HTML. """ - session.install(".[docs]") - session.chdir("docs") + session.install(".", "-r", "docs/requirements.txt") + build_dir = session.create_tmp() session.run( - f"python{session.python}", + f"{session.bin}/python{session.python}", "-Im", "sphinx", - "-b", + "--builder", "html", - "-d", - f"{session.bin}/../tmp/doctrees", - ".", - f"{session.bin}/../tmp/html", + "--write-all", + "-c", + "docs/", + "--doctree-dir", + f"{build_dir}/doctrees", + "docs/", + f"{build_dir}/html", ) clean() @@ -185,23 +196,21 @@ def docs_spellcheck(session: nox.Session) -> None: Spell-check the package's documentation. """ - session.install( - "pyenchant", - "sphinxcontrib-spelling", - ".[docs]", - ) + session.install(".", "-r", "docs/requirements.txt") + session.install("pyenchant", "sphinxcontrib-spelling") build_dir = session.create_tmp() - session.chdir("docs") session.run( - f"python{session.python}", + f"{session.bin}/python{session.python}", "-Im", "sphinx", "-W", # Promote warnings to errors, so that misspelled words fail the build. - "-b", + "--builder", "spelling", - "-d", + "-c", + "docs/", + "--doctree-dir", f"{build_dir}/doctrees", - ".", + "docs/", f"{build_dir}/html", # On Apple Silicon Macs, this environment variable needs to be set so # pyenchant can find the "enchant" C library. See @@ -218,7 +227,7 @@ def docs_spellcheck(session: nox.Session) -> None: # ----------------------------------------------------------------------------------- -@nox.session(python=["3.12"], tags=["formatters"]) +@nox.session(python=["3.13"], tags=["formatters"]) def format_black(session: nox.Session) -> None: """ Check code formatting with Black. @@ -240,7 +249,7 @@ def format_black(session: nox.Session) -> None: clean() -@nox.session(python=["3.12"], tags=["formatters"]) +@nox.session(python=["3.13"], tags=["formatters"]) def format_isort(session: nox.Session) -> None: """ Check import order with isort. @@ -266,7 +275,7 @@ def format_isort(session: nox.Session) -> None: # ----------------------------------------------------------------------------------- -@nox.session(python=["3.12"], tags=["linters", "security"]) +@nox.session(python=["3.13"], tags=["linters", "security"]) def lint_bandit(session: nox.Session) -> None: """ Lint code with the Bandit security analyzer. @@ -287,7 +296,7 @@ def lint_bandit(session: nox.Session) -> None: clean() -@nox.session(python=["3.12"], tags=["linters"]) +@nox.session(python=["3.13"], tags=["linters"]) def lint_flake8(session: nox.Session) -> None: """ Lint code with flake8. @@ -307,7 +316,7 @@ def lint_flake8(session: nox.Session) -> None: clean() -@nox.session(python=["3.12"], tags=["linters"]) +@nox.session(python=["3.13"], tags=["linters"]) def lint_pylint(session: nox.Session) -> None: """ Lint code with Pylint. @@ -324,7 +333,7 @@ def lint_pylint(session: nox.Session) -> None: # ----------------------------------------------------------------------------------- -@nox.session(python=["3.12"], tags=["packaging"]) +@nox.session(python=["3.13"], tags=["packaging"]) def package_build(session: nox.Session) -> None: """ Check that the package builds. @@ -336,7 +345,7 @@ def package_build(session: nox.Session) -> None: clean() -@nox.session(python=["3.12"], tags=["packaging"]) +@nox.session(python=["3.13"], tags=["packaging"]) def package_description(session: nox.Session) -> None: """ Check that the package description will render on the Python Package Index. @@ -360,7 +369,7 @@ def package_description(session: nox.Session) -> None: clean() -@nox.session(python=["3.12"], tags=["packaging"]) +@nox.session(python=["3.13"], tags=["packaging"]) def package_manifest(session: nox.Session) -> None: """ Check that the set of files in the package matches the set under version control. @@ -374,7 +383,7 @@ def package_manifest(session: nox.Session) -> None: clean() -@nox.session(python=["3.12"], tags=["packaging"]) +@nox.session(python=["3.13"], tags=["packaging"]) def package_pyroma(session: nox.Session) -> None: """ Check package quality with pyroma. @@ -385,7 +394,7 @@ def package_pyroma(session: nox.Session) -> None: clean() -@nox.session(python=["3.12"], tags=["packaging"]) +@nox.session(python=["3.13"], tags=["packaging"]) def package_wheel(session: nox.Session) -> None: """ Check the built wheel package for common errors. diff --git a/pdm.lock b/pdm.lock new file mode 100644 index 0000000..5872407 --- /dev/null +++ b/pdm.lock @@ -0,0 +1,262 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "tests"] +strategy = ["inherit_metadata"] +lock_version = "4.5.0" +content_hash = "sha256:5c91e0f67b6dc04dcd7901438e71cc33674d2782fce312dec1dcaf472162a54e" + +[[metadata.targets]] +requires_python = ">=3.9,<3.10" + +[[metadata.targets]] +requires_python = ">=3.10" + +[[package]] +name = "anyio" +version = "4.6.2.post1" +requires_python = ">=3.9" +summary = "High level compatibility layer for multiple asynchronous event loop implementations" +groups = ["default"] +dependencies = [ + "exceptiongroup>=1.0.2; python_version < \"3.11\"", + "idna>=2.8", + "sniffio>=1.1", + "typing-extensions>=4.1; python_version < \"3.11\"", +] +files = [ + {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, + {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, +] + +[[package]] +name = "argcomplete" +version = "3.5.1" +requires_python = ">=3.8" +summary = "Bash tab completion for argparse" +groups = ["tests"] +files = [ + {file = "argcomplete-3.5.1-py3-none-any.whl", hash = "sha256:1a1d148bdaa3e3b93454900163403df41448a248af01b6e849edc5ac08e6c363"}, + {file = "argcomplete-3.5.1.tar.gz", hash = "sha256:eb1ee355aa2557bd3d0145de7b06b2a45b0ce461e1e7813f5d066039ab4177b4"}, +] + +[[package]] +name = "certifi" +version = "2024.8.30" +requires_python = ">=3.6" +summary = "Python package for providing Mozilla's CA Bundle." +groups = ["default"] +files = [ + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["tests"] +marker = "sys_platform == \"win32\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "colorlog" +version = "6.9.0" +requires_python = ">=3.6" +summary = "Add colours to the output of Python's logging module." +groups = ["tests"] +dependencies = [ + "colorama; sys_platform == \"win32\"", +] +files = [ + {file = "colorlog-6.9.0-py3-none-any.whl", hash = "sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff"}, + {file = "colorlog-6.9.0.tar.gz", hash = "sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2"}, +] + +[[package]] +name = "distlib" +version = "0.3.9" +summary = "Distribution utilities" +groups = ["tests"] +files = [ + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" +groups = ["default"] +marker = "python_version < \"3.11\" and python_version >= \"3.9\"" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[[package]] +name = "filelock" +version = "3.16.1" +requires_python = ">=3.8" +summary = "A platform independent file lock." +groups = ["tests"] +files = [ + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, +] + +[[package]] +name = "h11" +version = "0.14.0" +requires_python = ">=3.7" +summary = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +groups = ["default"] +dependencies = [ + "typing-extensions; python_version < \"3.8\"", +] +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "1.0.6" +requires_python = ">=3.8" +summary = "A minimal low-level HTTP client." +groups = ["default"] +dependencies = [ + "certifi", + "h11<0.15,>=0.13", +] +files = [ + {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, + {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, +] + +[[package]] +name = "httpx" +version = "0.27.2" +requires_python = ">=3.8" +summary = "The next generation HTTP client." +groups = ["default"] +dependencies = [ + "anyio", + "certifi", + "httpcore==1.*", + "idna", + "sniffio", +] +files = [ + {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, + {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, +] + +[[package]] +name = "idna" +version = "3.10" +requires_python = ">=3.6" +summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["default"] +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[[package]] +name = "nox" +version = "2024.10.9" +requires_python = ">=3.8" +summary = "Flexible test automation." +groups = ["tests"] +dependencies = [ + "argcomplete<4,>=1.9.4", + "colorlog<7,>=2.6.1", + "packaging>=20.9", + "tomli>=1; python_version < \"3.11\"", + "virtualenv>=20.14.1", +] +files = [ + {file = "nox-2024.10.9-py3-none-any.whl", hash = "sha256:1d36f309a0a2a853e9bccb76bbef6bb118ba92fa92674d15604ca99adeb29eab"}, + {file = "nox-2024.10.9.tar.gz", hash = "sha256:7aa9dc8d1c27e9f45ab046ffd1c3b2c4f7c91755304769df231308849ebded95"}, +] + +[[package]] +name = "packaging" +version = "24.2" +requires_python = ">=3.8" +summary = "Core utilities for Python packages" +groups = ["tests"] +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +requires_python = ">=3.8" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["tests"] +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +requires_python = ">=3.7" +summary = "Sniff out which async library your code is running under" +groups = ["default"] +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "tomli" +version = "2.0.2" +requires_python = ">=3.8" +summary = "A lil' TOML parser" +groups = ["tests"] +marker = "python_version < \"3.11\" and python_version >= \"3.9\"" +files = [ + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["default"] +marker = "python_version < \"3.11\" and python_version >= \"3.9\"" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "virtualenv" +version = "20.27.1" +requires_python = ">=3.8" +summary = "Virtual Python Environment builder" +groups = ["tests"] +dependencies = [ + "distlib<1,>=0.3.7", + "filelock<4,>=3.12.2", + "importlib-metadata>=6.6; python_version < \"3.8\"", + "platformdirs<5,>=3.9.1", +] +files = [ + {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, + {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, +] diff --git a/pyproject.toml b/pyproject.toml index d1a22b3..b18be09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,11 @@ [build-system] -requires = ["setuptools>=61.0"] -build-backend = "setuptools.build_meta" +requires = ["pdm-backend"] +build-backend = "pdm.backend" [project] authors = [ - {name = "Michael Foord"}, - {name = "James Bennett"} + {name = "Michael Foord"}, + {name = "James Bennett"}, ] maintainers = [ {name = "James Bennett"} @@ -18,53 +18,38 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.3", "Topic :: Utilities", ] name = "akismet" description = "A Python interface to the Akismet spam-filtering service." dependencies = [ - "httpx", + "httpx", ] -dynamic = ["version"] keywords = ["akismet", "spam", "spam-filtering"] license = {text = "BSD-3-Clause"} readme = "README.rst" -requires-python = ">=3.8" +requires-python = ">=3.9" +version = "24.11.0a1" [project.urls] "Documentation" = "https://akismet.readthedocs.io" "Source Code" = "https://github.com/ubernostrum/akismet" -[project.optional-dependencies] -docs = [ - "furo", - "matplotlib", - "sphinx", - "sphinx-copybutton", - "sphinx-inline-tabs", - "sphinx-notfound-page", - "sphinxext-opengraph", -] -tests = [ - "coverage[toml]", -] +[dependency-groups] +tests = ["nox"] [tool.bandit] -# For reasons I do not understand, Bandit has decided to begin -# alerting on use of httpx without an explicit timeout, when httpx -# applies an automatic default timeout in that case. See -# https://github.com/PyCQA/bandit/issues/1175 for details; if and when -# they revert their alerts on httpx, the B113 check can be turned on -# again. +# B113 is only skipped right now because of a bug in Bandit. Bandit 1.8 should fix it: +# https://github.com/PyCQA/bandit/issues/1175 skips = ["B101", "B113"] [tool.black] -target-version = ["py38", "py39", "py310", "py311", "py312"] +target-version = ["py39", "py39", "py310", "py311", "py313"] [tool.coverage.paths] source = ["src", ".nox/tests_with_coverage*/**/site-packages"] @@ -85,11 +70,26 @@ ignore-init-module = true [tool.isort] profile = "black" +[tool.pdm] +distribution = true + +[tool.pdm.build] +source-includes = [ + ".editorconfig", + ".flake8", + ".pre-commit-config.yaml", + ".readthedocs.yaml", + "AUTHORS", + "CONTRIBUTING.rst", + "docs/", + "noxfile.py", + "pdm.lock", + "runtests.py", + "tests/", +] + [tool.pylint] disable = [ "duplicate-code", "protected-access", ] - -[tool.setuptools.dynamic] -version = {attr = "akismet._version.LIBRARY_VERSION"} diff --git a/src/akismet/__init__.py b/src/akismet/__init__.py index 410e9f0..129d1ad 100644 --- a/src/akismet/__init__.py +++ b/src/akismet/__init__.py @@ -102,9 +102,6 @@ from ._legacy_client import Akismet from ._sync_client import SyncClient from ._test_clients import TestAsyncClient, TestSyncClient -from ._version import LIBRARY_VERSION - -__version__ = LIBRARY_VERSION __all__ = [ "APIKeyError", diff --git a/src/akismet/_common.py b/src/akismet/_common.py index 0a382cf..dba5a0d 100644 --- a/src/akismet/_common.py +++ b/src/akismet/_common.py @@ -10,10 +10,10 @@ import sys import textwrap import typing +from importlib.metadata import version import httpx -from . import _version from ._exceptions import APIKeyError, ConfigurationError, ProtocolError # Private constants. @@ -60,7 +60,7 @@ # ------------------------------------------------------------------------------- USER_AGENT = ( - f"akismet.py/{_version.LIBRARY_VERSION} | Python/" + f"akismet.py/{version('akismet')} | Python/" f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}" ) diff --git a/src/akismet/_version.py b/src/akismet/_version.py deleted file mode 100644 index ff68b03..0000000 --- a/src/akismet/_version.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -Library version number. - -""" - -# SPDX-License-Identifier: BSD-3-Clause - -# This is set here instead of in common.py or __init__.py because it's read dynamically -# by setuptools during the package build, and both common.py and __init__.py (which -# imports common.py) need to import the third-party httpx library, which is not -# available during package build (it only becomes available after package install). -LIBRARY_VERSION = "24.5.1" diff --git a/tox.ini b/tox.ini deleted file mode 100644 index b68e9ba..0000000 --- a/tox.ini +++ /dev/null @@ -1,188 +0,0 @@ -# This is a configuration file for running tests, linters and other -# code-quality checks, using Tox (https://tox.readthedocs.io/), which -# allows configuring and automatically running many different test -# environments and checks, each in a separate Python virtual -# environment (and each potentially using a different version of -# Python). -# -# Using this file requires having tox installed -- "pip install tox" -# or refer to Tox's own documentation -- and a functioning -# installation of at least one targeted Python version. Running "tox" -# with no command-line arguments will attempt to run all environments -# against all targeted Python versions, and will fail if any Python -# versions are missing. To select only certain test environments to -# run, use the "-e" command-line flag and pass either a single -# environment name, or a comma-separated list of environment names. To -# see all available environments with their descriptions, run: -# "tox -v 1 --listenvs" - - -# Base configuration: list of environments and Python versions. -################################################################################ - -# Environment matrix. -[tox] -envlist = - py{37,38,39,310} - black - check-description - check-manifest - docs - flake8 - isort - spelling - -# Configuration for running on GitHub Actions via tox-gh-actions. -[gh-actions] -python = - 3.6: py36 - 3.7: py37 - 3.8: py38 - 3.9: py39 - 3.10: py310, black, check-description, check-manifest, docs, flake8, isort, spelling - - -# The base test environment -- runs the unit test suite with coverage. -################################################################################ -[testenv] -description = Run tests with coverage report. -allowlist_externals = - find - rm -# Python silences deprecation warnings by default, but we want to see -# them during test runs. -setenv = - PYTHONWARNINGS=once::DeprecationWarning -# Ensure each virtualenv always has latest pip, so output doesn't get -# cluttered with messages about needing to upgrade it. Note that tox's -# 'download=true' option doesn't quite do the same thing: it ensures -# pip/setuptools/wheel get upgraded at virtualenv creation time, but -# will not upgrade them when reusing an already-created virtualenv. -commands_pre = - {envpython} -m pip install --upgrade pip -# Many test runs will leave behind some type of artifact -- Python -# bytecode, packaging-related files, coverage data -- which should be -# removed before the next run in order to ensure a clean starting -# point. The commands below run after the main test commands of each -# virtualenv, and perform this cleanup. -commands_post = - find {toxinidir}/tests -type f -name "*.pyc" -delete - find {toxinidir}/tests -type d -name "__pycache__" -delete - find {toxinidir}/src -type f -name "*.pyc" -delete - find {toxinidir}/src -type d -name "__pycache__" -delete - find {toxinidir}/src -type f -path "*.egg-info*" -delete - find {toxinidir}/src -type d -path "*.egg-info" -delete - rm -f {toxinidir}/.coverage -commands = - {posargs:pytest -vv --ignore=src --cov=akismet --cov-report term-missing} -deps = - pytest - pytest-cov -passenv = - TEST_AKISMET_API_KEY - TEST_AKISMET_BLOG_URL - -# Documentation checks. -################################################################################ - -# Runs an HTML build of the documentation, and fails if there's an -# error in building it. -[testenv:docs] -description = Check that the documentation can build. -basepython = python3.10 -changedir = {toxinidir}/docs -commands = - sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html -deps = - sphinx - sphinx_rtd_theme - -# Runs a spelling checker over the documentation, and if misspelled -# words are found, fails the build and outputs a list of -# them. Requires the 'enchant' C library preinstalled on the target -# system. -[testenv:spelling] -description = Spell-check documentation. -basepython = python3.10 -changedir = {toxinidir}/docs -# This is the only env where we silence deprecation warnings, because -# we'd already catch any from our actual codebase elsewhere and in -# this env we are asking Sphinx to promote warnings to errors in order -# to fail the build on anything caught by the spelling checker. -setenv = - PYTHONWARNINGS=ignore::DeprecationWarning -commands = - sphinx-build -W -b spelling -d {envtmpdir}/doctrees . {envtmpdir}/html -deps = - sphinx - sphinx_rtd_theme - pyenchant - sphinxcontrib-spelling - - -# Linters. -################################################################################ - -# Runs the Black code formatter over the entire code base, and fails -# if Black thinks any files need to be reformatted. -[testenv:black] -description = Check code formatting using Black. -basepython = python3.10 -changedir = {toxinidir} -deps = black -commands = - black --line-length 88 --check --diff {toxinidir}/src {toxinidir}/tests {toxinidir}/docs {toxinidir} - -# Runs the flake8 linter over the entire code base, and fails if -# flake8 finds any problems. -[testenv:flake8] -description = Lint code with flake8. -basepython = python3.10 -changedir = {toxinidir} -deps = flake8 -commands = - flake8 {toxinidir}/src/akismet.py {toxinidir}/tests - -# Runs the isort import linter over the entire code base, and fails if -# any problems are found. -[testenv:isort] -description = Lint imports with isort. -basepython = python3.10 -changedir = {toxinidir} -deps = isort -commands = - isort --check-only --diff {toxinidir}/src {toxinidir}/tests - - -# Packaging checks. -################################################################################ - -# Builds the package and runs 'twine check' to ensure it will render -# correctly when uploaded to the Python Package Index, or fail if not. -[testenv:check-description] -description = Check that the package description will render on the Python Package Index. -basepython = python3.10 -changedir = {toxinidir} -skip_install = true -deps = - twine -# In this environment we always want latest wheel in addition to -# latest pip. -commands_pre = - {envpython} -m pip install --upgrade pip setuptools wheel -commands = - {envpython} -m pip wheel -w {envtmpdir}/build --no-deps . - twine check {envtmpdir}/build/* - -# Runs check-manifest, a tool that builds the package and compares the -# files in the package to the files under version control, and fails -# if any version-controlled files do not end up in the package. -[testenv:check-manifest] -description = Check that the set of packaged files matches the set of version-controlled files. -basepython = python3.10 -changedir = {toxinidir} -skip_install = true -deps = - check-manifest -commands = - check-manifest --verbose