Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-requests-cache for
openSUSE:Factory checked in at 2026-06-16 13:57:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-requests-cache (Old)
and /work/SRC/openSUSE:Factory/.python-requests-cache.new.1981 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-requests-cache"
Tue Jun 16 13:57:37 2026 rev:13 rq:1359666 version:1.3.2
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-requests-cache/python-requests-cache.changes
2026-05-25 22:00:28.350021315 +0200
+++
/work/SRC/openSUSE:Factory/.python-requests-cache.new.1981/python-requests-cache.changes
2026-06-16 14:02:22.323555856 +0200
@@ -1,0 +2,5 @@
+Mon Jun 15 20:43:00 UTC 2026 - Dirk Müller <[email protected]>
+
+- add avoid-vacuum-in-transaction.patch
+
+-------------------------------------------------------------------
New:
----
avoid-vacuum-in-transaction.patch
----------(New B)----------
New:
- add avoid-vacuum-in-transaction.patch
----------(New E)----------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-requests-cache.spec ++++++
--- /var/tmp/diff_new_pack.UCbDpq/_old 2026-06-16 14:02:24.347640252 +0200
+++ /var/tmp/diff_new_pack.UCbDpq/_new 2026-06-16 14:02:24.359640753 +0200
@@ -24,6 +24,8 @@
Group: Development/Languages/Python
URL: https://github.com/requests-cache/requests-cache
Source:
https://github.com/requests-cache/requests-cache/archive/refs/tags/v%{version}.tar.gz#/requests-cache-%{version}.tar.gz
+# PATCH-FIX-UPSTREAM
+Patch1: avoid-vacuum-in-transaction.patch
BuildRequires: %{python_module hatchling >= 1.0.0}
BuildRequires: %{python_module pip}
BuildRequires: fdupes
@@ -79,7 +81,7 @@
take a look at `CacheControl <https://github.com/ionrock/cachecontrol>`_.
%prep
-%setup -q -n requests-cache-%{version}
+%autosetup -p1 -n requests-cache-%{version}
%build
%pyproject_wheel
++++++ avoid-vacuum-in-transaction.patch ++++++
>From 096255138016baeda45616783c2f16cf7410c4f6 Mon Sep 17 00:00:00 2001
From: Jordan Cook <[email protected]>
Date: Sat, 6 Jun 2026 11:48:31 -0500
Subject: [PATCH] Fix SQLite vacuum (can't run in transaction)
---
requests_cache/backends/sqlite.py | 9 +++-
tests/integration/test_sqlite.py | 73 ++++++++++++++++++++++++-------
2 files changed, 63 insertions(+), 19 deletions(-)
diff --git a/requests_cache/backends/sqlite.py
b/requests_cache/backends/sqlite.py
index d4116fbd..5b6d7ee4 100644
--- a/requests_cache/backends/sqlite.py
+++ b/requests_cache/backends/sqlite.py
@@ -447,8 +447,13 @@ def sorted(
yield result
def vacuum(self):
- with self.connection(commit=True) as con:
- con.execute('VACUUM')
+ # VACUUM cannot run inside a transaction; acquire the lock and run it
directly
+ with self._lock:
+ if self._connection:
+ if self._active_transaction:
+ self._connection.commit()
+ self._active_transaction = False
+ self._connection.execute('VACUUM')
def _format_sequence(values: Collection) -> Tuple[str, List]:
diff --git a/tests/integration/test_sqlite.py b/tests/integration/test_sqlite.py
index ad1f0a1a..72812997 100644
--- a/tests/integration/test_sqlite.py
+++ b/tests/integration/test_sqlite.py
@@ -5,14 +5,14 @@
from os.path import join
from tempfile import NamedTemporaryFile, gettempdir
from threading import Thread
-from unittest.mock import patch
+from unittest.mock import MagicMock, patch
import pytest
from platformdirs import user_cache_dir
from requests_cache.backends import BaseCache, SQLiteCache, SQLiteDict
from requests_cache.backends.sqlite import MEMORY_URI
-from requests_cache.models import CachedResponse
+from requests_cache.models import CachedRequest, CachedResponse
from requests_cache.policy import utcnow
from tests.conftest import skip_pypy
from tests.integration.base_cache_test import BaseCacheTest
@@ -170,28 +170,44 @@ def test_write_acquire_lock(self):
assert mock_write.call_count == 1
def test_write_retry_acquire_lock(self):
- """Acquiring the lock should retry until it succeeds"""
+ """Acquiring the lock should retry BEGIN IMMEDIATE until it succeeds"""
cache = self.init_cache()
with patch.object(cache, '_connection') as mock_connection:
mock_connection.execute.side_effect = [sqlite3.OperationalError] *
10 + [None]
with cache._acquire_sqlite_lock():
pass
- assert mock_connection.execute.call_count == 11
+ begin_calls = [
+ c for c in mock_connection.execute.call_args_list if 'BEGIN
IMMEDIATE' in str(c)
+ ]
+ assert len(begin_calls) == 11
- def test_write_retry__other_errors(self):
- """Errors other than 'OperationalError: database is locked' should not
be retried"""
+ def test_write__error(self):
+ """Errors from write operations should propagate"""
cache = self.init_cache()
-
- error_1 = sqlite3.OperationalError('no more rows available')
- with patch.object(cache, '_write', side_effect=error_1):
+ with patch.object(cache, '_write',
side_effect=sqlite3.OperationalError('DB is on fire')):
with pytest.raises(sqlite3.OperationalError):
cache['key_1'] = 'value_1'
-
- error_2 = sqlite3.DatabaseError('hard drive is on fire')
- with patch.object(cache, '_write', side_effect=error_2):
+ with patch.object(cache, '_write',
side_effect=sqlite3.DatabaseError('HDD also on fire')):
with pytest.raises(sqlite3.DatabaseError):
cache['key_1'] = 'value_1'
+ def test_vacuum__no_connection(self):
+ cache = self.init_cache()
+ cache._connection = None
+ cache.vacuum()
+
+ def test_vacuum__commits_active_transaction(self):
+ cache = self.init_cache()
+ mock_con = MagicMock()
+ cache._connection = mock_con
+ cache._active_transaction = True
+
+ cache.vacuum()
+
+ mock_con.commit.assert_called_once()
+ mock_con.execute.assert_called_once_with('VACUUM')
+ assert cache._active_transaction is False
+
@skip_pypy
@pytest.mark.parametrize('limit', [None, 50])
def test_sorted__by_size(self, limit):
@@ -203,8 +219,8 @@ def test_sorted__by_size(self, limit):
cache[f'key_{i}'] = f'value_{i}_{suffix}'
# Sorted items should be in ascending order by size
- items = list(cache.sorted(key='size'))
- assert len(items) == limit or 100
+ items = list(cache.sorted(key='size', limit=limit))
+ assert len(items) == (limit or 100)
prev_item = None
for item in items:
@@ -241,8 +257,8 @@ def test_sorted__by_expires(self, limit):
cache[f'key_{i}'] = response
# Sorted items should be in ascending order by expiration time
- items = list(cache.sorted(key='expires'))
- assert len(items) == limit or 100
+ items = list(cache.sorted(key='expires', limit=limit))
+ assert len(items) == (limit or 100)
prev_item = None
for item in items:
@@ -328,10 +344,11 @@ def test_clear__failure(self, mock_unlink, mock_clear):
"""When a corrupted cache prevents a normal DROP TABLE, clear() should
still succeed"""
session = self.init_session(clear=False)
session.cache.responses['key_1'] = 'value_1'
+ db_path = session.cache.responses.db_path
session.cache.clear()
assert len(session.cache.responses) == 0
- assert mock_unlink.call_count == 1
+ mock_unlink.assert_called_once_with(db_path)
@patch.object(BaseCache, 'clear', side_effect=IOError)
def test_clear__file_already_deleted(self, mock_clear):
@@ -378,6 +395,28 @@ def test_delete__skip_vacuum(self):
session.cache.delete('key_1', 'key_2', vacuum=False)
mock_vacuum.assert_not_called()
+ def test_vacuum__frees_disk_space(self):
+ """vacuum() should reclaim disk space after bulk deletion (regression
test for #1156)"""
+ session = self.init_session()
+ db_path = session.cache.responses.db_path
+
+ for i in range(200):
+ cr = CachedResponse(status_code=200,
url=f'https://example.com/{i}')
+ cr.request = CachedRequest(method='GET',
url=f'https://example.com/{i}')
+ cr._content = b'x' * 50_000
+ session.cache.save_response(cr, cache_key=f'k{i}')
+
+ size_before = os.path.getsize(db_path)
+ session.cache.delete(older_than=timedelta(seconds=-1))
+ assert session.cache.responses.count() == 0
+
+ session.cache.responses.vacuum()
+ size_after = os.path.getsize(db_path)
+
+ assert size_after < size_before / 10, (
+ f'vacuum() did not reclaim disk space: {size_before} ->
{size_after} bytes'
+ )
+
@patch.object(SQLiteDict, 'sorted')
def test_filter__expired(self, mock_sorted):
"""Filtering by expired should use a more efficient SQL query"""