From 69225bfec35f3d813a46847b9aea01eb49520592 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sun, 18 May 2025 11:34:48 -0400 Subject: [PATCH 01/16] Makefile: remove docs from all target The 'all' make target builds the 'html' documentation target. According to the GNU coding standards, the 'all' target "need not rebuild any documentation". Since building the docs implies installing the .[docs] optional python dependencies, it can cause unexpected errors for builders. So remove the 'html' target dependency. Signed-off-by: Riparian Commit --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a672253..9826d40 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ htmldir ?= $(docdir)/html # PHONY TARGETS # ################# -all : html +all : $(PYTHON3) -m build --wheel --outdir $(builddir) --verbose .PHONY : all From a6be2d38d96dad08418af14b46c2998fb2c78774 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sun, 18 May 2025 13:41:52 -0400 Subject: [PATCH 02/16] rule34Py: fix py3.9 incompatibility in type hinting In several places in rule34Py, we use a type hinting syntax to declare a union of types, with the pipe character. This is only a valid syntax in >py3.10. It causes a TypeError in versions prior to that. Import and use the 'Union' type from the typing module, to provide backwards compatibility. Signed-off-by: Riparian Commit --- rule34Py/rule34.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rule34Py/rule34.py b/rule34Py/rule34.py index 5534fee..ffd0e5f 100644 --- a/rule34Py/rule34.py +++ b/rule34Py/rule34.py @@ -19,6 +19,7 @@ """A module containing the top-level Rule34 API client class.""" from collections.abc import Iterator +from typing import Union from urllib.parse import parse_qs import os import urllib.parse as urlparse @@ -66,7 +67,7 @@ class rule34Py(): _base_site_rate_limiter = LimiterAdapter(per_second=1) #: Client captcha clearance token. Defaults to either the value of the ``R34_CAPTCHA_CLEARANCE`` environment variable; or None, if the environment variable is not asserted. #: Can be overridden at runtime by the user. - captcha_clearance: str | None = os.environ.get("R34_CAPTCHA_CLEARANCE", None) + captcha_clearance: Union[str, None] = os.environ.get("R34_CAPTCHA_CLEARANCE", None) #: The ``requests.Session`` object used when the client makes HTML requests. session: requests.Session = None #: The ``User-Agent`` HTML header value used when the client makes HTML requests. @@ -157,7 +158,7 @@ def get_pool(self, pool_id: int) -> Pool: response.raise_for_status() return PoolPage.pool_from_html(response.text) - def get_post(self, post_id: int) -> Post | None: + def get_post(self, post_id: int) -> Union[Post, None]: """Get a Post by its ID. Args: @@ -202,7 +203,7 @@ def icame(self) -> list["ICame"]: def iter_search( self, tags: list[str] = [], - max_results: (int | None) = None, + max_results: Union[int, None] = None, ) -> Iterator[Post]: """Iterate through Post search results, one element at a time. @@ -301,7 +302,7 @@ def random_post_id(self) -> int: def search(self, tags: list[str] = [], - page_id: int | None = None, + page_id: Union[int, None] = None, limit: int = SEARCH_RESULT_MAX, ) -> list[Post]: """Search for posts. From 8b9fccf468b53f49c3127f2758e15d66e357dc85 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sun, 18 May 2025 13:52:20 -0400 Subject: [PATCH 03/16] pyproject.toml: remove version constraints on deps Unless we have some specific information that a dependency prior to some version does not work in the project, we should not arbitrarily restrict the dep version. Remove all '>=' dependency constraints in the pyproject.toml. Signed-off-by: Riparian Commit --- pyproject.toml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5edd9cf..98c7f01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,10 +16,10 @@ maintainers = [ { name = "b3yc0d3", email = "b3yc0d3@gmail.com" } ] dependencies = [ - "requests-ratelimiter >= 0.7.0", - "beautifulsoup4 >= 4.9.3", - "lxml >= 4.6.4", - "requests >= 2.27.1", + "requests-ratelimiter", + "beautifulsoup4", + "lxml", + "requests", ] classifiers = [ "Development Status :: 4 - Beta", @@ -48,16 +48,16 @@ build-backend = "setuptools.build_meta" [project.optional-dependencies] dev = [ - "ruff >= 0.11.10", + "ruff", ] test = [ - "pytest >= 8.3.2", - "responses >= 0.25.3", + "pytest", + "responses", ] docs = [ - "sphinx >= 8.2.3", - "sphinx-mdinclude >= 0.6.2", - "sphinx-rtd-theme >= 3.0.2", + "sphinx", + "sphinx-mdinclude", + "sphinx-rtd-theme", ] [tool.ruff.lint] From 517ca703a2ce03365d4dac3ec54da7939a9e2109 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sun, 18 May 2025 14:10:08 -0400 Subject: [PATCH 04/16] docs: support docs builds on py3.9 The tomllib module was added to the standard python distribution starting in version 3.11. Trying to build the docs on versions prior to that will throw an import error. Conditionally prefer to use the third-party 'tomli' module for python runtimes prior to 3.11. Tomli provides a similar interface and intentional backport support for TOML parsing on old pythons. It is licensed under MIT. Signed-off-by: Riparian Commit --- docs/conf.py | 7 ++++++- pyproject.toml | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 52ff878..7d2900a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -8,7 +8,12 @@ from datetime import datetime from pathlib import Path -import tomllib as toml +import sys + +if sys.version_info < (3, 11): + import tomli as toml +else: + import tomllib as toml PROJECT_ROOT = Path(__file__).parent.resolve() / ".." diff --git a/pyproject.toml b/pyproject.toml index 98c7f01..b8e6dd6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ docs = [ "sphinx", "sphinx-mdinclude", "sphinx-rtd-theme", + "tomli; python_version < \"3.11\"", ] [tool.ruff.lint] From ffdaec4acd0ae132a866d388ecc5e5993ab5de2a Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sun, 18 May 2025 10:16:46 -0400 Subject: [PATCH 05/16] PR test on multiple python versions The project claims to support python versions back to 3.9, but these aren't necessarily the versions that developers test their changes on. Upgrade the PR check pipeline to use matrix testing of python 3.9 and the latest python runtime on both windows and linux. Also move linting into its own workflow stage, prior to the build/testing stages. Only upload artifacts from the latest-python build/test jobs, since they are probably the most interesting. Signed-off-by: Riparian Commit --- .github/actions/build-project/action.yml | 34 ++++++++++++------ .github/workflows/pr-checks.yml | 45 +++++++++++++++--------- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/.github/actions/build-project/action.yml b/.github/actions/build-project/action.yml index 69aee02..1efc640 100644 --- a/.github/actions/build-project/action.yml +++ b/.github/actions/build-project/action.yml @@ -1,21 +1,35 @@ -name: Build the project -description: Installs project dependencies and builds the project +name: Build and test +description: Builds and tests the project inputs: + python_version: + default: "" # empty will make setup-python default to the env python latest_python: default: false runs: using: "composite" steps: - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: ">=3.5" - check-latest: ${{ inputs.latest_python }} + - name: Install host tooling + shell: bash + run: | + python -m pip install --upgrade setuptools build + python -m pip install . .[dev] .[docs] .[test] + pip freeze \ + --exclude rule34Py \ + >build/requirements.txt - - name: Build documentation + - name: Build wheel and dist shell: bash run: | - python3 -m pip install .[docs] - make html + make all + make dist + + - name: Run unit tests + shell: bash + run: make check + + - name: Build documentation + shell: bash + run: make html + \ No newline at end of file diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 78540d9..0ca2931 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -6,39 +6,50 @@ on: - "**" jobs: - build-linux: + source-quality: runs-on: ubuntu-latest - + name: Source Quality Checks steps: - name: Checkout code uses: actions/checkout@v4 - - name: Build the project - uses: ./.github/actions/build-project - with: - latest_python: true # always use the latest python in PR checks - - - name: Upload build artifacts - uses: actions/upload-artifact@v4 + - name: Set up python + uses: actions/setup-python@v5 with: - name: build-${{ github.run_id }}-${{ github.run_number }} - path: ./build - retention-days: 14 + python-version: '3.x' - - name: Lint the project + - name: Lint sources shell: bash run: | python -m pip install .[dev] make lint + build-and-test: + needs: source-quality + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + python-version: ['3.x', '3.9'] + os: [ubuntu-latest, windows-latest] - build-windows: - runs-on: windows-latest + name: Build ${{ matrix.os }}-py${{ matrix.python-version }} steps: - name: Checkout code uses: actions/checkout@v4 - - name: Build the project + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Build and test uses: ./.github/actions/build-project + + - name: Upload build artifacts + if: matrix.python-version == '3.x' + uses: actions/upload-artifact@v4 with: - latest_python: true # always use the latest python in PR checks + name: build.${{ github.run_id }}-${{ github.run_number }}.${{ matrix.os }}-py${{ matrix.python-version || 'latest' }} + path: ./build + retention-days: 14 From 6fa59dc016de43a5ab25a2a151d3896234f2e529 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sun, 18 May 2025 15:22:09 -0400 Subject: [PATCH 06/16] pyproject.toml: upgrade minimum python to 3.9 Python 3.9 is the earliest python version that is still supported by python upstream. And it is the earliest version that we reliably test on GH runners (without going to great lengths to manually install an earlier python runtime). So upgrade the minimum supported python version in the package metadata to 3.9. Signed-off-by: Riparian Commit --- pyproject.toml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b8e6dd6..ec82f66 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ authors = [ { name = "Tal A. Baskin", email = "talbaskin.business@gmail.com" }, { name = "ripariancommit", email = "ripariancommit@protonmail.com" } ] -requires-python = ">=3.5" +requires-python = ">=3.9" maintainers = [ { name = "b3yc0d3", email = "b3yc0d3@gmail.com" } ] @@ -23,13 +23,11 @@ dependencies = [ ] classifiers = [ "Development Status :: 4 - Beta", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "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.13", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Operating System :: OS Independent" ] From e55f9774e49b449e57b7611891a861eef20b9797 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sun, 18 May 2025 15:47:19 -0400 Subject: [PATCH 07/16] pr-checks.yml: add pr-quality check stage The upstream rule34Py repo requires that PRs opened against it target the 'develop' ref. Add a pr-quailty check stage to validate the above assertion. Signed-off-by: Riparian Commit --- .github/workflows/pr-checks.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 0ca2931..8ddb4eb 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -2,10 +2,23 @@ name: PR Checks on: pull_request: - branches: - - "**" + types: [opened, edited, synchronize, reopened] jobs: + pr-quality: + name: PR Quality Checks + # Validates the quality of the PR and its constituent commits, against + # the policies of the upstream repo. + runs-on: ubuntu-latest + steps: + - name: Check PR target branch + run: | + echo "PR is targeting branch: ${{ github.event.pull_request.base.ref }}" + if [ "${{ github.event.pull_request.base.ref }}" != "develop" ]; then + echo "❌ Pull request must target 'develop' branch!" + exit 1 + fi + source-quality: runs-on: ubuntu-latest name: Source Quality Checks @@ -25,7 +38,7 @@ jobs: make lint build-and-test: - needs: source-quality + needs: [pr-quality, source-quality] runs-on: ${{ matrix.os }} strategy: fail-fast: false From 57bdb34c8f6c201bff9fedd45931312b3bef0c01 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sun, 18 May 2025 16:28:25 -0400 Subject: [PATCH 08/16] .github: rework pipelines The PR Check pipeline should contain only the logic that we want to run on PR checks - like linting and policy checking. Then we should have a CI pipeline that gates commits into the 'develop' branch based on whether they pass the test suite. Then we should have a CD pipeline that does things like deploy the GH pages. --- .github/actions/build-project/action.yml | 27 ++++++++------ .github/workflows/cd-master.yml | 45 ++++++++++++++++++++++++ .github/workflows/ci-develop.yml | 36 +++++++++++++++++++ .github/workflows/gh-pages.yml | 28 --------------- .github/workflows/pr-checks.yml | 37 ++++--------------- 5 files changed, 105 insertions(+), 68 deletions(-) create mode 100644 .github/workflows/cd-master.yml create mode 100644 .github/workflows/ci-develop.yml delete mode 100644 .github/workflows/gh-pages.yml diff --git a/.github/actions/build-project/action.yml b/.github/actions/build-project/action.yml index 1efc640..9b85ccb 100644 --- a/.github/actions/build-project/action.yml +++ b/.github/actions/build-project/action.yml @@ -2,15 +2,19 @@ name: Build and test description: Builds and tests the project inputs: - python_version: - default: "" # empty will make setup-python default to the env python - latest_python: - default: false + python-version: + default: '3.x' runs: using: "composite" steps: - - name: Install host tooling + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python-version }} + + - name: Install host python dependencies shell: bash run: | python -m pip install --upgrade setuptools build @@ -25,11 +29,14 @@ runs: make all make dist - - name: Run unit tests - shell: bash - run: make check - - name: Build documentation shell: bash run: make html - \ No newline at end of file + + - name: Upload build artifacts + if: ${{ inputs.python-version == '3.x' }} + uses: actions/upload-artifact@v4 + with: + name: build.${{ github.run_id }}-${{ github.run_number }}.${{ runner.os }}-py${{ inputs.python-version }} + path: ./build + retention-days: 14 diff --git a/.github/workflows/cd-master.yml b/.github/workflows/cd-master.yml new file mode 100644 index 0000000..9040e65 --- /dev/null +++ b/.github/workflows/cd-master.yml @@ -0,0 +1,45 @@ +name: Continuous Delivery +# This workflow performs post-push actions on the 'master' branch. +# It should build the final version of the branch artifacts, that might be +# released to PyPi or GH. And it should build and deploy the GH Pages artifacts. + +on: + push: + branches: + - master + +permissions: + contents: write + pages: write + id-token: write + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Build the project + uses: ./.github/actions/build-project + with: + python-version: '3.x' + + gh-pages: + needs: build + runs-on: ubuntu-latest + + steps: + - name: Checkout build artifacts + uses: actions/download-artifact@v4 + with: + path: ./build + pattern: build.*.Linux-py3.x + merge-multiple: true + + - name: Deploy to Github Pages + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./build/html diff --git a/.github/workflows/ci-develop.yml b/.github/workflows/ci-develop.yml new file mode 100644 index 0000000..a467509 --- /dev/null +++ b/.github/workflows/ci-develop.yml @@ -0,0 +1,36 @@ +name: CI Testing +# This pipeline builds and tests the project. +# Commits that pass this workflow can be assumed to be functionally correct, +# per the current state of the mock responses registry. + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + push: + branches: + - develop + +jobs: + build-and-test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + python-version: ['3.x', '3.9'] + os: [ubuntu-latest, windows-latest] + + name: Build ${{ matrix.os }}-py${{ matrix.python-version }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Build the project + uses: ./.github/actions/build-project + with: + python-version: ${{ matrix.python-version }} + + - name: Run unit tests + shell: bash + run: | + python -m pip install .[test] + make check diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml deleted file mode 100644 index b479959..0000000 --- a/.github/workflows/gh-pages.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Publish GH Pages - -on: - push: - branches: - - master - -permissions: - contents: write - pages: write - id-token: write - -jobs: - build-docs: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Build the project - uses: ./.github/actions/build-project - - - name: Deploy to Github Pages - uses: peaceiris/actions-gh-pages@v4 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./build/html diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 8ddb4eb..3eef43f 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -1,7 +1,14 @@ name: PR Checks +# This workflow runs on PRs opened on the repo's 'develop' branch. +# It's purpose is to check that repository policies around PR and source quality +# and syntax are honored by developers. Commits which pass this workflow are +# quality enough that they can be merged. +# This workflow does not verify code correctness or run tests. on: pull_request: + branches: + - develop types: [opened, edited, synchronize, reopened] jobs: @@ -36,33 +43,3 @@ jobs: run: | python -m pip install .[dev] make lint - - build-and-test: - needs: [pr-quality, source-quality] - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - python-version: ['3.x', '3.9'] - os: [ubuntu-latest, windows-latest] - - name: Build ${{ matrix.os }}-py${{ matrix.python-version }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - name: Build and test - uses: ./.github/actions/build-project - - - name: Upload build artifacts - if: matrix.python-version == '3.x' - uses: actions/upload-artifact@v4 - with: - name: build.${{ github.run_id }}-${{ github.run_number }}.${{ matrix.os }}-py${{ matrix.python-version || 'latest' }} - path: ./build - retention-days: 14 From 268216df9ae8cfc05c3e389f07cb0304a4dbd716 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Thu, 22 May 2025 19:34:40 -0400 Subject: [PATCH 09/16] developer-guide: add note about legacy setuptools This project still supports python versions old enough to be before general support for TOML files, and the pyproject.toml specification. builders running python 3.9 might have difficulty following the tool setup instructions without upgrading their setuptools version. Signed-off-by: Riparian Commit --- docs/dev/developer-guide.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/dev/developer-guide.rst b/docs/dev/developer-guide.rst index d12d522..5601712 100644 --- a/docs/dev/developer-guide.rst +++ b/docs/dev/developer-guide.rst @@ -65,6 +65,11 @@ The following instructions are written on the assumption that you are building i Build output will be placed in the ``:build/`` directory in your workspace. +.. Note:: + + If you are using a very old python environment, your installed version of setuptools and python may not be aware of how to process pyproject.toml files. + If this seems to be the case, try upgrading your build tools by calling ``python -m pip install --upgrade setuptools build``. + Other ``make`` targets are supported to ``clean`` the project and build other artifacts. Generally, the project ``Makefile`` honors the `GNU Standard Targets `_ specification. From b2c15c330654f232e17df34de03d399c42440451 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Thu, 22 May 2025 20:03:58 -0400 Subject: [PATCH 10/16] .gitignore: ignore ruff cache The ruff linter generates a .ruff_cache directory. It is a temporary file that should be ignored. Signed-off-by: Riparian Commit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index ed8b632..51e2516 100755 --- a/.gitignore +++ b/.gitignore @@ -159,3 +159,5 @@ Thumbs.db # End of https://www.toptal.com/developers/gitignore/api/python + +**/.ruff_cache From ca3102e34372c673e81e921ebeeeea36b6a22026 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Thu, 22 May 2025 20:05:44 -0400 Subject: [PATCH 11/16] Remove debug.py This project is now well-tested by unit tests and autotesting. The debug.py script can be removed in favor of the new testing. Signed-off-by: Riparian Commit --- debug.py | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100755 debug.py diff --git a/debug.py b/debug.py deleted file mode 100755 index 56b9897..0000000 --- a/debug.py +++ /dev/null @@ -1,31 +0,0 @@ -from rule34Py import rule34Py -import json - - -r34Py = rule34Py() - -print(r34Py.version) - -post = r34Py.get_post(4931536) -print(post.thumbnail) - -icame = r34Py.icame() -print(icame) - -comments = r34Py.get_comments(13647055) -print(comments) - -search = r34Py.search(["neko"], page_id=2, limit=50) -print(search) - -pool = r34Py.get_pool(25938) -print(pool) - -rpost = r34Py.random_post() -print(rpost) - -tag_map = r34Py.tag_map() -print(tag_map) - -top_tags = r34Py.top_tags() -print(top_tags) From c4b38eac4b09608214e756589ff6a3c9cbdca6db Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Tue, 3 Jun 2025 19:23:36 -0400 Subject: [PATCH 12/16] CHANGELOG: update through PR #27 Signed-off-by: Riparian Commit --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cfa342..a2e766d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,19 +12,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added captcha-compliance capabilities. You can now pass the client your captcha clearance token by completing the captcha in your browser, opening the response header, and writing your `cf_clearance` token into the client's `rule34Py.captcha_clearance` attribute and setting the client's `user_agent` attribute to match your browser. - Alternatively, set your execution environment's `R34_CAPTCHA_CLEARANCE` and `R34_USER_AGENT` variables to the appropriate values. The client will read form them during initialization. + - See [this user guide](https://b3yc0d3.github.io/rule34Py/guides/captcha-clearance.html) for more information. (#24) - Added a rate limiter for requests to the rule34.xxx base site (the PHP endpoint). By default, the client will now limit API calls that use this endpoint to 1 per second. - This behavior can be disabled by setting `rule34Py.set_base_site_rate_limit(False)`. - There is no rate limit on the api.rule34.xxx endpoint, which is assumed to handle rate-limiting on the server-side. - This new feature requires the `requests-ratelimiter` module. +- Added project documentation via sphinx docs. See: https://b3yc0d3.github.io/rule34Py/. It can be built by calling `make html`. (#24) ### Changed - Changed the behavior of the `rule34Py.random_post()` method to function more like the website. The method now accepts no `tag` parameters, and returns a random post ID from all posts on the site. Users who want to use the old behavior of returning a random post from the first 1000 tag-search results are directed to do something like `random.choice(rule34Py.search([tags...]))`. - Changed the `rule34Py.get_pool()` method to return a `Pool` object containing more complete information about a Pool. - The Pool's post ids can be accessed via the `Pool.posts` attribute. +- Moved the `:examples/` python recipes into tutorial documentation in the new sphinx documentation (`:docs/tutorials`). (#24) ### Deprecated + +- Deprecated support for python runtimes 3.5 to 3.8, as they are EOL. The minimum supported python version is now 3.9. (#27) + ### Removed + +- Removed the deprecated `legacy.setup.py` file. Users are instructed to upgrade their setuptools installation and use `pyproject.toml` to build the project. +- Removed the `debug.py` file. Users are instructed to use the `make check` Makefile target to run the project's test suite. (#27) + ### Fixed ### Security From 0381a3fb6bf46be22c50fbd9d87724459ac9a35e Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sat, 7 Jun 2025 16:37:11 -0400 Subject: [PATCH 13/16] Makefile: use PYTHON_BUILD consistently Signed-off-by: Riparian Commit --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9826d40..672e98c 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ htmldir ?= $(docdir)/html ################# all : - $(PYTHON3) -m build --wheel --outdir $(builddir) --verbose + $(PYTHON_BUILD) --wheel --outdir $(builddir) --verbose .PHONY : all From 1277133966d6f410954f84081945a4b396bed7b2 Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sat, 7 Jun 2025 16:38:17 -0400 Subject: [PATCH 14/16] Makefile: remove --wheel from dist target The dist target should only build the source distribution, per the GNU standard. To get both the wheel and sdist, simply call ``` make all make dist ``` Signed-off-by: Riparian Commit --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 672e98c..7849ad2 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ clean : mostlyclean dist : - $(PYTHON_BUILD) --sdist --wheel --outdir $(builddir) + $(PYTHON_BUILD) --sdist --outdir $(builddir) .PHONY : dist publish : clean dist check From a1cf145b366ae7f9637311ef1d1baada153d497f Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sat, 7 Jun 2025 16:42:57 -0400 Subject: [PATCH 15/16] pyproject.toml: restrict python version <4.0 The requests-ratelimiter module "requires" python >=3.7,<4.0. Because it is a dependency of this project, when you try to process the project dependencies with poetry, you get a satisfaction warning that the python versions required by this project (>3.9) technically could include runtimes 4.0+, breaking compat. It's an odd rqeuirement, that honestly should be fixed in upstream requests-ratelimiter. Until we can get that upstreamed, just add '<4.0' to our python requirement to resolve the error. Signed-off-by: Riparian Commit --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ec82f66..8997c49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ authors = [ { name = "Tal A. Baskin", email = "talbaskin.business@gmail.com" }, { name = "ripariancommit", email = "ripariancommit@protonmail.com" } ] -requires-python = ">=3.9" +requires-python = ">=3.9,<4.0" maintainers = [ { name = "b3yc0d3", email = "b3yc0d3@gmail.com" } ] From 54c0fb492d4a62d2bbafeefc996b7d2727a655fb Mon Sep 17 00:00:00 2001 From: Riparian Commit Date: Sat, 7 Jun 2025 19:21:16 -0400 Subject: [PATCH 16/16] Makefile: clean up rules The Twine utility is now used to publish the project artifacts, but it is not included in the pyproject dependencies. Add it to the deps. Use a small python script to programmatically extract the project name and version from the pyproject.toml file, since that is the source of the artifact names. Generally clean up the Makefile targets. Signed-off-by: Riparian Commit --- Makefile | 69 ++++++++++++++++++++++++++------------- pyproject.toml | 1 + scripts/read_pyproject.py | 24 ++++++++++++++ 3 files changed, 72 insertions(+), 22 deletions(-) create mode 100755 scripts/read_pyproject.py diff --git a/Makefile b/Makefile index 7849ad2..1693a88 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,29 @@ +# Extract the project name and version from the pyproject.toml file. +PROJECT = $(shell $(PYTHON3) scripts/read_pyproject.py project/name | tr 'A-Z' 'a-z') +VERSION = $(shell $(PYTHON3) scripts/read_pyproject.py project/version) -.DEFAULT_GOAL = all - -PROJECT = rule34py -VERSION = $(shell git describe --tags) - -TWINE = twine +# Binaries PYTHON3 ?= python3 +PYTEST = $(PYTHON3) -m pytest PYTHON_BUILD = $(PYTHON3) -m build RUFF = $(PYTHON3) -m ruff -SPHINX_BUILD = $(PYTHON3) -m sphinx -PYTEST = $(PYTHON3) -m pytest +SPHINX = $(PYTHON3) -m sphinx +TWINE = $(PYTHON3) -m twine +# Source files builddir ?= build srcdir = rule34Py +dist_files = \ + $(srcdir) \ + LICENSE \ + NOTICE.md \ + pyproject.toml \ + README.md \ + +sdist = $(builddir)/$(PROJECT)-$(VERSION).tar.gz # The python sdist. +wheels = $(builddir)/$(PROJECT)-$(VERSION)-py3-none-any.whl # The python wheels. + # Installation Directories prefix ?= /usr/local @@ -21,24 +31,36 @@ docdir ?= $(prefix)/share/doc/$(project) htmldir ?= $(docdir)/html +.DEFAULT_GOAL = all + + # REAL TARGETS # ################ +$(wheels) &: $(dist_files) + $(PYTHON_BUILD) --outdir $(builddir) --wheel + + +$(sdist) : $(dist_files) + $(PYTHON_BUILD) --outdir $(builddir) --sdist + # PHONY TARGETS # ################# -all : - $(PYTHON_BUILD) --wheel --outdir $(builddir) --verbose +# Build all binary targets necessary for installation. +# Does not build documentation or source distributions. +all : $(wheels) .PHONY : all -check : - $(TWINE) check dist/* - PYTHONPATH=$(srcdir)/.. $(PYTEST) tests/unit/ +# Run pre-installation tests on the built artifacts. +check : all + PYTHONPATH=$(builddir)/lib $(PYTEST) tests/unit/ .PHONY : check +# Remove all files created as a result of building the project. clean : mostlyclean find ./ -depth -path '**/.pytest_cache*' -print -delete find ./ -depth -path '**/__pycache__*' -print -delete @@ -46,29 +68,32 @@ clean : mostlyclean .PHONY : clean -dist : - $(PYTHON_BUILD) --sdist --outdir $(builddir) +# Build the redistributable source archive. +dist : $(sdist) .PHONY : dist -publish : clean dist check - $(TWINE) upload dist/* -.PHONY : publish - -distclean : clean -.PHONY : distclean +# Check and publish the python package index artifacts. +publish : $(sdist) $(wheels) + $(TWINE) check $(^) + $(TWINE) upload $(^) +.PHONY : publish +# Build the project's HTML documentation. html : - $(SPHINX_BUILD) --builder html docs $(builddir)/html + $(SPHINX) --builder html docs $(builddir)/html .PHONY : html +# Lint the project source for quality. lint : $(RUFF) check $(srcdir) .PHONY : lint +# Remove files created as a result of building the project, except those that +# rarely need to be rebuilt. mostlyclean : rm -rf $(builddir) find ./ -depth -path '**/rule34Py.egg-info*' -print -delete diff --git a/pyproject.toml b/pyproject.toml index 8997c49..385c179 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ build-backend = "setuptools.build_meta" [project.optional-dependencies] dev = [ "ruff", + "twine", ] test = [ "pytest", diff --git a/scripts/read_pyproject.py b/scripts/read_pyproject.py new file mode 100755 index 0000000..1e9d0e9 --- /dev/null +++ b/scripts/read_pyproject.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +"""Generate a Makefile includes file which exports variables from the pyproject.toml.""" + +from pathlib import Path +import sys + +if sys.version_info < (3, 11): + import tomli as toml +else: + import tomllib as toml + +PROJECT_ROOT = Path(__file__).parents[1].resolve() + +with open(PROJECT_ROOT / "pyproject.toml", "rb") as fp_pyproject: + pyproject_data = toml.load(fp_pyproject) + + +for path in sys.argv[1:]: + path_elements = path.split("/") + + cursor = pyproject_data + for path_element in path_elements: + cursor = cursor[path_element] + sys.stdout.write(str(cursor) + "\n")