diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d08f9fb..e22c0f4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -10,12 +10,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.13' + cache: pip - name: Install ruff run: | diff --git a/.github/workflows/specs.yml b/.github/workflows/specs.yml index ca3b64c..cd07851 100644 --- a/.github/workflows/specs.yml +++ b/.github/workflows/specs.yml @@ -12,15 +12,16 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} + cache: pip - name: Install dependencies run: | diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7abafa7..9d24834 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,14 @@ master ------ +7.3.0 (2026-09-07) +------------------ + +- add ``PaymentRequiredError`` for HTTP 402 responses +- raise the ``requests`` minimum to ``2.32.5`` +- pin ``ruff`` to ``0.15.22`` +- test on Python 3.9–3.14 + 7.2.0 (2026-06-09) ------------------ diff --git a/DEVELOPMENT.rst b/DEVELOPMENT.rst index f138658..fa2e9b2 100644 --- a/DEVELOPMENT.rst +++ b/DEVELOPMENT.rst @@ -24,7 +24,7 @@ Test $ make test -Runs ``python3 -m unittest -v castle.test``. CI runs the same suite on Python 3.9–3.13 via GitHub Actions (``.github/workflows/specs.yml``). +Runs ``python3 -m unittest -v castle.test``. CI runs the same suite on Python 3.9–3.14 via GitHub Actions (``.github/workflows/specs.yml``). Linting ------- diff --git a/README.rst b/README.rst index b6bbdd0..a45dc00 100644 --- a/README.rst +++ b/README.rst @@ -190,6 +190,7 @@ All exceptions inherit from ``CastleError``. The most useful ones: - ``InvalidRequestTokenError`` — the request token is missing or invalid - ``InvalidParametersError`` — 422 response with validation details - ``RateLimitError`` — 429 response; back off and retry +- ``PaymentRequiredError`` — 402 response - ``UnauthorizedError`` — 401; bad API secret - ``InternalServerError`` — 5xx response from Castle - ``WebhookVerificationError`` — webhook signature did not match diff --git a/castle/core/process_response.py b/castle/core/process_response.py index e8d7669..93e216d 100644 --- a/castle/core/process_response.py +++ b/castle/core/process_response.py @@ -10,12 +10,14 @@ InternalServerError, InvalidRequestTokenError, RateLimitError, + PaymentRequiredError, ) from castle.logger import Logger RESPONSE_ERRORS = { 400: BadRequestError, 401: UnauthorizedError, + 402: PaymentRequiredError, 403: ForbiddenError, 404: NotFoundError, 419: UserUnauthorizedError, diff --git a/castle/errors.py b/castle/errors.py index 5911ea5..d2fc39a 100644 --- a/castle/errors.py +++ b/castle/errors.py @@ -55,5 +55,9 @@ class RateLimitError(APIError): pass +class PaymentRequiredError(APIError): + pass + + class InternalServerError(APIError): pass diff --git a/castle/test/core/process_response_test.py b/castle/test/core/process_response_test.py index 87f0dce..6974d02 100644 --- a/castle/test/core/process_response_test.py +++ b/castle/test/core/process_response_test.py @@ -13,6 +13,7 @@ InternalServerError, InvalidRequestTokenError, RateLimitError, + PaymentRequiredError, ) @@ -91,6 +92,10 @@ def test_verify_419(self): with self.assertRaises(UserUnauthorizedError): CoreProcessResponse(response(status_code=419)).verify() + def test_verify_402(self): + with self.assertRaises(PaymentRequiredError): + CoreProcessResponse(response(status_code=402)).verify() + def test_verify_429(self): with self.assertRaises(RateLimitError): CoreProcessResponse(response(status_code=429)).verify() diff --git a/castle/version.py b/castle/version.py index 52dac8d..8d0dc2c 100644 --- a/castle/version.py +++ b/castle/version.py @@ -1 +1 @@ -VERSION = '7.2.0' +VERSION = '7.3.0' diff --git a/pyproject.toml b/pyproject.toml index 82867e1..266fd2c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ authors = [ requires-python = ">=3.9" dynamic = ["version"] dependencies = [ - "requests>=2.31", + "requests>=2.32.5", ] classifiers = [ "Environment :: Web Environment", @@ -27,6 +27,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ] [project.urls] @@ -36,7 +37,7 @@ Changelog = "https://github.com/castle/castle-python/blob/master/CHANGELOG.rst" [project.optional-dependencies] test = ["responses>=0.23"] -lint = ["ruff>=0.6"] +lint = ["ruff==0.15.22"] [tool.setuptools.dynamic] version = { attr = "castle.version.VERSION" }