Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ updates:
directory: /
schedule:
interval: daily
cooldown:
default-days: 7
open-pull-requests-limit: 99
rebase-strategy: "disabled"
groups:
Expand Down
32 changes: 13 additions & 19 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,22 @@ jobs:
runs-on: ubuntu-latest

permissions:
# Used to authenticate to PyPI via OIDC.
# Used to sign the release's artifacts with sigstore-python.
id-token: write

# Used to attach signing artifacts to the published release.
contents: write
id-token: write # For Trusted Publishing + attestations.
contents: write # For uploading release assets.

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version-file: pyproject.toml
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false

- name: deps
run: python -m pip install -U build
- name: Install the latest version of uv
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2
with:
enable-cache: false

- name: build
run: python -m build
- name: build
run: make dist

- name: publish
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
- name: publish
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0

24 changes: 13 additions & 11 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ on:

permissions: {}

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
tests:
name: "Python ${{ matrix.python-version }} ${{ matrix.os }}"
Expand All @@ -18,25 +22,23 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
os: ["macos-latest", "windows-latest", "ubuntu-latest"]

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false

- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
- uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: "${{ matrix.python-version }}"
allow-prereleases: true

- name: "Install dependencies"
run: |
python -VV
python -m site
python -m pip install --upgrade pip setuptools wheel
python -m pip install --upgrade virtualenv tox tox-gh-actions
- name: Install the latest version of uv
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2

- name: "Run tox targets for ${{ matrix.python-version }}"
run: "python -m tox"
- name: Run tests for ${{ matrix.python-version }}
run: |
make bootstrap
make test
22 changes: 4 additions & 18 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,15 @@ permissions: {}

jobs:
zizmor:
name: zizmor latest via PyPI
name: Run zizmor 🌈
runs-on: ubuntu-latest
permissions:
security-events: write
# required for workflows in private repositories
contents: read
actions: read
security-events: write # For uploading security analysis results.
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false

- name: Install the latest version of uv
uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0

- name: Run zizmor 🌈
run: uvx zizmor --format sarif . > results.sarif
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
with:
sarif_file: results.sarif
category: zizmor
uses: zizmorcore/zizmor-action@e673c3917a1aef3c65c972347ed84ccd013ecda4 # v0.2.0
31 changes: 14 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,24 @@
# SPDX-License-Identifier: Apache-2.0

VENV=.venv
VENV_CMD=python3 -m venv
ACTIVATE = $(VENV)/bin/activate

$(VENV)/bin/pip:
$(VENV_CMD) $(VENV)
bootstrap:
uv sync --extra dev

bootstrap: $(VENV)/bin/pip
$(VENV)/bin/pip install -e .[dev]
lint:
uv run ruff check
uv run mypy cachecontrol

format:
$(VENV)/bin/codespell
$(VENV)/bin/ruff check --fix
$(VENV)/bin/ruff format
uv run codespell
uv run ruff check --fix
uv run ruff format

doc: $(VENV)/bin/sphinx-build
. $(ACTIVATE);
cd docs && make html
. $(ACTIVATE) && \
cd docs && \
make html

clean: clean-build clean-pyc clean-test

Expand All @@ -35,19 +36,15 @@ clean-pyc:
find . -name '__pycache__' -exec rm -fr {} +

clean-test:
rm -fr .tox/
rm -f .coverage
rm -fr htmlcov/

test-all:
$(VENV)/bin/tox

test:
$(VENV)/bin/py.test
uv run py.test

coverage:
$(VENV)/bin/py.test --cov cachecontrol
uv run py.test --cov cachecontrol

dist: clean
$(VENV)/bin/python -m build
uv build
ls -l dist
8 changes: 5 additions & 3 deletions cachecontrol/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
Make it easy to import from cachecontrol without long namespaces.
"""

__author__ = "Eric Larson"
__email__ = "eric@ionrock.org"
__version__ = "0.14.3"
import importlib.metadata

from cachecontrol.adapter import CacheControlAdapter
from cachecontrol.controller import CacheController
from cachecontrol.wrapper import CacheControl

__author__ = "Eric Larson"
__email__ = "eric@ionrock.org"
__version__ = importlib.metadata.version("cachecontrol")

__all__ = [
"__author__",
"__email__",
Expand Down
1 change: 0 additions & 1 deletion cachecontrol/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from __future__ import annotations

import functools
import types
import weakref
import zlib
from typing import TYPE_CHECKING, Any, Collection, Mapping
Expand Down
4 changes: 3 additions & 1 deletion cachecontrol/filewrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import TYPE_CHECKING, Any, Callable

if TYPE_CHECKING:
from collections.abc import Buffer
from http.client import HTTPResponse


Expand All @@ -31,7 +32,7 @@ class CallbackFileWrapper:
"""

def __init__(
self, fp: HTTPResponse, callback: Callable[[bytes], None] | None
self, fp: HTTPResponse, callback: Callable[[Buffer], None] | None
) -> None:
self.__buf = NamedTemporaryFile("rb+", delete=True)
self.__fp = fp
Expand Down Expand Up @@ -68,6 +69,7 @@ def __is_fp_closed(self) -> bool:
return False

def _close(self) -> None:
result: Buffer
if self.__callback:
if self.__buf.tell() == 0:
# Empty file:
Expand Down
6 changes: 6 additions & 0 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
Release Notes
===============

0.14.4
======

* Explicitly support Python 3.14.
* Drop support for Python 3.9.

0.14.3
======

Expand Down
25 changes: 13 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
[build-system]
requires = ["flit_core >=3.11,<4"]
build-backend = "flit_core.buildapi"
requires = ["uv_build>=0.9.6,<0.10.0"]
build-backend = "uv_build"

[tool.flit.module]
name = "cachecontrol"
[tool.uv.build-backend]
source-include = ["tests/"]
module-name = "cachecontrol"
module-root = ""

[tool.flit.sdist]
include = ["tests/"]

[project]
name = "CacheControl"
dynamic = ["version"]
version = "0.14.3"
description = "httplib2 caching for requests"
readme = "README.rst"
license = "Apache-2.0"
Expand All @@ -24,16 +24,16 @@ classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Web Environment",
"Operating System :: OS Independent",
"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",
"Programming Language :: Python :: 3.14",
"Topic :: Internet :: WWW/HTTP",
]
keywords = ["requests", "http", "caching", "web"]
dependencies = ["requests >= 2.16.0", "msgpack >= 0.5.2, < 2.0.0"]
requires-python = ">=3.9"
requires-python = ">=3.10"

[project.urls]
Homepage = "https://pypi.org/project/CacheControl/"
Expand All @@ -48,17 +48,18 @@ redis = ["redis>=2.10.5"]
# Development extras.
dev = [
"CacheControl[filecache,redis]",
"build",
"cherrypy",
"codespell[tomli]",
# See: https://github.com/cherrypy/cherrypy/issues/2070
# See: https://github.com/cherrypy/cheroot/issues/769
"cheroot >= 11.1.2",
"codespell",
"furo",
"mypy",
"pytest",
"pytest-cov",
"ruff",
"sphinx",
"sphinx-copybutton",
"tox",
"types-redis",
"types-requests",
]
Expand Down
44 changes: 18 additions & 26 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
#
# SPDX-License-Identifier: Apache-2.0

from pprint import pformat

import os
import socket

import pytest
from pprint import pformat

import cherrypy
import pytest


class SimpleApp:
Expand Down Expand Up @@ -126,7 +124,22 @@ def __call__(self, env, start_response):

@pytest.fixture(scope="session")
def server():
return cherrypy.server
cherrypy.tree.graft(SimpleApp(), "/")

ip, port = get_free_port()

cherrypy.config.update({"server.socket_host": ip, "server.socket_port": port})

# turn off logging
logger = cherrypy.log.access_log
if logger:
logger.removeHandler(logger.handlers[0])

cherrypy.server.start()

yield cherrypy.server

cherrypy.server.stop()


@pytest.fixture()
Expand All @@ -141,24 +154,3 @@ def get_free_port():
s.close()
ip = os.environ.get("WEBTEST_SERVER_BIND", "127.0.0.1")
return ip, port


def pytest_configure(config):
cherrypy.tree.graft(SimpleApp(), "/")

ip, port = get_free_port()

cherrypy.config.update({"server.socket_host": ip, "server.socket_port": port})

# turn off logging
logger = cherrypy.log.access_log
logger.removeHandler(logger.handlers[0])

cherrypy.server.start()


def pytest_unconfigure(config):
try:
cherrypy.server.stop()
except: # noqa: E722
pass
Loading