Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-queuelib for openSUSE:Factory
checked in at 2026-08-25 13:19:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-queuelib (Old)
and /work/SRC/openSUSE:Factory/.python-queuelib.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-queuelib"
Tue Aug 25 13:19:37 2026 rev:9 rq:1373450 version:1.10.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-queuelib/python-queuelib.changes
2026-03-23 17:12:43.904088173 +0100
+++
/work/SRC/openSUSE:Factory/.python-queuelib.new.1258/python-queuelib.changes
2026-08-25 13:19:42.031135312 +0200
@@ -1,0 +2,12 @@
+Mon Aug 24 16:47:34 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to 1.10.0:
+ * Added clear(), which removes every item from a queue while
+ keeping it open
+ * Fixed RoundRobinQueue.pop() dropping falsy items
+ * Added support for Python 3.15
+- Refresh summary and description to also mention the in-memory
+ queues
+- List installed files explicitly instead of globbing sitelib
+
+-------------------------------------------------------------------
Old:
----
queuelib-1.9.0.tar.gz
New:
----
queuelib-1.10.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-queuelib.spec ++++++
--- /var/tmp/diff_new_pack.h4Oxzn/_old 2026-08-25 13:19:43.360182112 +0200
+++ /var/tmp/diff_new_pack.h4Oxzn/_new 2026-08-25 13:19:43.364182253 +0200
@@ -18,9 +18,9 @@
%{?sle15_python_module_pythons}
Name: python-queuelib
-Version: 1.9.0
+Version: 1.10.0
Release: 0
-Summary: Collection of Persistent (Disk-Based) Queues
+Summary: Collection of In-Memory and Persistent (Disk-Based) Queues
License: BSD-3-Clause
URL: https://github.com/scrapy/queuelib
Source:
https://files.pythonhosted.org/packages/source/q/queuelib/queuelib-%{version}.tar.gz
@@ -38,10 +38,12 @@
%python_subpackages
%description
-Queuelib is a collection of persistent (disk-based) queues for Python.
+Queuelib is a Python library that implements object collections which are
+stored in memory or persisted to disk, provide a simple API, and run fast.
-Queuelib goals are speed and simplicity. It was originally part of the
-`Scrapy framework`_ and stripped out on its own library.
+Queuelib provides collections for queues (FIFO), stacks (LIFO), queues sorted
+by priority and queues that are emptied in a round-robin fashion. Queuelib
+collections are not thread-safe.
%prep
%setup -q -n queuelib-%{version}
@@ -59,5 +61,6 @@
%files %{python_files}
%doc README.rst NEWS
%license LICENSE
-%{python_sitelib}/*
+%{python_sitelib}/queuelib
+%{python_sitelib}/queuelib-%{version}*-info
++++++ queuelib-1.9.0.tar.gz -> queuelib-1.10.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/NEWS new/queuelib-1.10.0/NEWS
--- old/queuelib-1.9.0/NEWS 2020-02-02 01:00:00.000000000 +0100
+++ new/queuelib-1.10.0/NEWS 2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,15 @@
Queuelib release notes
======================
+Version 1.10.0
+---------------
+(released on 2026-08-24)
+
+* Added ``clear()``, to remove every item from a queue while keeping it open
+* Fixed ``RoundRobinQueue.pop()`` dropping falsy items
+* Added support for Python 3.15
+* Improved linting and CI configuration
+
Version 1.9.0
-------------
(released on 2026-01-29)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/PKG-INFO new/queuelib-1.10.0/PKG-INFO
--- old/queuelib-1.9.0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
+++ new/queuelib-1.10.0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
-Metadata-Version: 2.4
+Metadata-Version: 2.5
Name: queuelib
-Version: 1.9.0
+Version: 1.10.0
Summary: Collection of persistent (disk-based) and non-persistent
(memory-based) queues
Project-URL: Homepage, https://github.com/scrapy/queuelib
Project-URL: Source, https://github.com/scrapy/queuelib
@@ -19,6 +19,7 @@
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
+Classifier: Programming Language :: Python :: 3.15
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Requires-Python: >=3.10
@@ -159,11 +160,130 @@
>>> rr.pop()
b'd'
+Clearing a queue
+================
-Mailing list
-============
+``clear()`` removes every item from a queue, freeing the disk space that they
+used, and leaves the queue open and usable::
+
+ >>> q.clear()
+ >>> len(q)
+ 0
+
+``PriorityQueue`` and ``RoundRobinQueue`` also close their internal queues, the
+same way that ``pop()`` does when one of them becomes empty.
+
+Disk persistence
+================
+
+``FifoDiskQueue`` and ``LifoDiskQueue`` write their items to the path they get
+on instantiation, so that a queue can be resumed later, even by a different
+process.
+
+Each class uses that path differently:
+
+- ``FifoDiskQueue`` uses a directory, which it creates, together with any
+ missing parent directory. Items go into chunk files (``q00000``,
+ ``q00001``, etc.), each holding up to ``chunksize`` items, and the queue
+ also keeps an ``info.json`` file there for its own bookkeeping.
+
+- ``LifoDiskQueue`` uses a single file, whose parent directory must already
+ exist.
+
+The layout and the contents of those files are an implementation detail that
+may change in any release. Do not read or write them yourself, and do not
+expect a queue written by one version of Queuelib to be readable by a
+different one.
+
+Always close disk queues
+------------------------
+
+While a disk queue is open, its bookkeeping (number of items, read and write
+positions) only lives in memory, and ``close()`` is what writes it to disk.
+Queuelib never calls ``fsync()`` either, and ``LifoDiskQueue`` writes items
+through a buffered file object, so the most recent items may not have reached
+the disk at all.
+
+Calling ``close()`` is hence mandatory::
+
+ from contextlib import closing
+
+ with closing(FifoDiskQueue("queuedir")) as q:
+ q.push(b'a')
+
+If a process ends without calling ``close()``, the queue on disk keeps the
+bookkeeping that the last ``close()`` call wrote, which no longer matches the
+files. Items pushed since then become unreachable, and using the queue again
+is unsafe: it may report a wrong length, return items that had already been
+popped, delete files that still contain items, or raise ``OSError``. Queuelib
+offers no way to repair or to recover such a queue.
+
+Empty queues delete their files
+-------------------------------
+
+``close()`` on an empty queue deletes its file, or, in the case of
+``FifoDiskQueue``, its chunk files and its ``info.json`` file, and also its
+directory if nothing else remains in it. Using that same path again creates a
+new, empty queue.
+
+FifoDiskQueue frees disk space one chunk at a time
+--------------------------------------------------
+
+``FifoDiskQueue`` deletes a chunk file once every item in it has been popped.
+Until then, popped items keep using disk space, so a queue uses up to
+``chunksize`` items worth of disk space on top of the items that it holds.
+
+Lower ``chunksize`` to lower that overhead, at the cost of more chunk files and
+more file operations. For example, a queue that holds 400 items of 1 MB each
+uses about 100 GB of disk space with the default ``chunksize`` of 100000, and
+about 800 MB with a ``chunksize`` of 400.
+
+Reopening a FifoDiskQueue keeps its chunk size
+----------------------------------------------
+
+``FifoDiskQueue`` stores its ``chunksize`` when creating a queue, and reuses
+the stored value when reopening one, ignoring the ``chunksize`` parameter.
+
+Use one queue object per path at a time
+---------------------------------------
+
+Queuelib does not lock the files that it uses. On top of not being
+thread-safe, a given path must not be used by more than one open queue object
+at a time, in the same process or not. Such queue objects overwrite each
+other's items and bookkeeping; for example, two ``FifoDiskQueue`` objects on
+the same directory return the same items, and their ``close()`` calls may
+raise ``FileNotFoundError``.
+
+Persisting a PriorityQueue or a RoundRobinQueue
+-----------------------------------------------
+
+``PriorityQueue`` and ``RoundRobinQueue`` do not write anything to disk
+themselves; their persistence comes entirely from the queues that ``qfactory``
+builds, and it is up to ``qfactory`` to map a priority or a key to a valid
+path.
+
+Their ``close()`` method returns the priorities or keys whose underlying queue
+was not empty. Storing that value is your responsibility, and so is passing it
+back as ``startprios`` or ``start_domains`` on the next run::
+
+ >>> import json
+ >>> from queuelib import FifoDiskQueue, PriorityQueue
+ >>> qfactory = lambda priority: FifoDiskQueue('queue-dir-%s' % priority)
+ >>> pq = PriorityQueue(qfactory)
+ >>> pq.push(b'a', 3)
+ >>> active = pq.close()
+ >>> with open('active.json', 'w') as f:
+ ... json.dump(active, f)
+ ...
+ >>> with open('active.json') as f:
+ ... startprios = json.load(f)
+ ...
+ >>> pq = PriorityQueue(qfactory, startprios)
+ >>> pq.pop()
+ b'a'
-Use the `scrapy-users`_ mailing list for questions about Queuelib.
+Priorities and keys that you do not pass back are not detected, and the items
+in their queues stay on disk, unreachable.
Bug tracker
===========
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/README.rst
new/queuelib-1.10.0/README.rst
--- old/queuelib-1.9.0/README.rst 2020-02-02 01:00:00.000000000 +0100
+++ new/queuelib-1.10.0/README.rst 2020-02-02 01:00:00.000000000 +0100
@@ -133,11 +133,130 @@
>>> rr.pop()
b'd'
+Clearing a queue
+================
-Mailing list
-============
+``clear()`` removes every item from a queue, freeing the disk space that they
+used, and leaves the queue open and usable::
-Use the `scrapy-users`_ mailing list for questions about Queuelib.
+ >>> q.clear()
+ >>> len(q)
+ 0
+
+``PriorityQueue`` and ``RoundRobinQueue`` also close their internal queues, the
+same way that ``pop()`` does when one of them becomes empty.
+
+Disk persistence
+================
+
+``FifoDiskQueue`` and ``LifoDiskQueue`` write their items to the path they get
+on instantiation, so that a queue can be resumed later, even by a different
+process.
+
+Each class uses that path differently:
+
+- ``FifoDiskQueue`` uses a directory, which it creates, together with any
+ missing parent directory. Items go into chunk files (``q00000``,
+ ``q00001``, etc.), each holding up to ``chunksize`` items, and the queue
+ also keeps an ``info.json`` file there for its own bookkeeping.
+
+- ``LifoDiskQueue`` uses a single file, whose parent directory must already
+ exist.
+
+The layout and the contents of those files are an implementation detail that
+may change in any release. Do not read or write them yourself, and do not
+expect a queue written by one version of Queuelib to be readable by a
+different one.
+
+Always close disk queues
+------------------------
+
+While a disk queue is open, its bookkeeping (number of items, read and write
+positions) only lives in memory, and ``close()`` is what writes it to disk.
+Queuelib never calls ``fsync()`` either, and ``LifoDiskQueue`` writes items
+through a buffered file object, so the most recent items may not have reached
+the disk at all.
+
+Calling ``close()`` is hence mandatory::
+
+ from contextlib import closing
+
+ with closing(FifoDiskQueue("queuedir")) as q:
+ q.push(b'a')
+
+If a process ends without calling ``close()``, the queue on disk keeps the
+bookkeeping that the last ``close()`` call wrote, which no longer matches the
+files. Items pushed since then become unreachable, and using the queue again
+is unsafe: it may report a wrong length, return items that had already been
+popped, delete files that still contain items, or raise ``OSError``. Queuelib
+offers no way to repair or to recover such a queue.
+
+Empty queues delete their files
+-------------------------------
+
+``close()`` on an empty queue deletes its file, or, in the case of
+``FifoDiskQueue``, its chunk files and its ``info.json`` file, and also its
+directory if nothing else remains in it. Using that same path again creates a
+new, empty queue.
+
+FifoDiskQueue frees disk space one chunk at a time
+--------------------------------------------------
+
+``FifoDiskQueue`` deletes a chunk file once every item in it has been popped.
+Until then, popped items keep using disk space, so a queue uses up to
+``chunksize`` items worth of disk space on top of the items that it holds.
+
+Lower ``chunksize`` to lower that overhead, at the cost of more chunk files and
+more file operations. For example, a queue that holds 400 items of 1 MB each
+uses about 100 GB of disk space with the default ``chunksize`` of 100000, and
+about 800 MB with a ``chunksize`` of 400.
+
+Reopening a FifoDiskQueue keeps its chunk size
+----------------------------------------------
+
+``FifoDiskQueue`` stores its ``chunksize`` when creating a queue, and reuses
+the stored value when reopening one, ignoring the ``chunksize`` parameter.
+
+Use one queue object per path at a time
+---------------------------------------
+
+Queuelib does not lock the files that it uses. On top of not being
+thread-safe, a given path must not be used by more than one open queue object
+at a time, in the same process or not. Such queue objects overwrite each
+other's items and bookkeeping; for example, two ``FifoDiskQueue`` objects on
+the same directory return the same items, and their ``close()`` calls may
+raise ``FileNotFoundError``.
+
+Persisting a PriorityQueue or a RoundRobinQueue
+-----------------------------------------------
+
+``PriorityQueue`` and ``RoundRobinQueue`` do not write anything to disk
+themselves; their persistence comes entirely from the queues that ``qfactory``
+builds, and it is up to ``qfactory`` to map a priority or a key to a valid
+path.
+
+Their ``close()`` method returns the priorities or keys whose underlying queue
+was not empty. Storing that value is your responsibility, and so is passing it
+back as ``startprios`` or ``start_domains`` on the next run::
+
+ >>> import json
+ >>> from queuelib import FifoDiskQueue, PriorityQueue
+ >>> qfactory = lambda priority: FifoDiskQueue('queue-dir-%s' % priority)
+ >>> pq = PriorityQueue(qfactory)
+ >>> pq.push(b'a', 3)
+ >>> active = pq.close()
+ >>> with open('active.json', 'w') as f:
+ ... json.dump(active, f)
+ ...
+ >>> with open('active.json') as f:
+ ... startprios = json.load(f)
+ ...
+ >>> pq = PriorityQueue(qfactory, startprios)
+ >>> pq.pop()
+ b'a'
+
+Priorities and keys that you do not pass back are not detected, and the items
+in their queues stay on disk, unreachable.
Bug tracker
===========
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/pyproject.toml
new/queuelib-1.10.0/pyproject.toml
--- old/queuelib-1.9.0/pyproject.toml 2020-02-02 01:00:00.000000000 +0100
+++ new/queuelib-1.10.0/pyproject.toml 2020-02-02 01:00:00.000000000 +0100
@@ -19,6 +19,7 @@
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
@@ -42,7 +43,7 @@
]
[tool.bumpversion]
-current_version = "1.9.0"
+current_version = "1.10.0"
commit = true
tag = true
tag_name = "v{new_version}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/queuelib/__init__.py
new/queuelib-1.10.0/queuelib/__init__.py
--- old/queuelib-1.9.0/queuelib/__init__.py 2020-02-02 01:00:00.000000000
+0100
+++ new/queuelib-1.10.0/queuelib/__init__.py 2020-02-02 01:00:00.000000000
+0100
@@ -1,4 +1,4 @@
-__version__ = "1.9.0"
+__version__ = "1.10.0"
from queuelib.pqueue import PriorityQueue
from queuelib.queue import FifoDiskQueue, LifoDiskQueue
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/queuelib/pqueue.py
new/queuelib-1.10.0/queuelib/pqueue.py
--- old/queuelib-1.9.0/queuelib/pqueue.py 2020-02-02 01:00:00.000000000
+0100
+++ new/queuelib-1.10.0/queuelib/pqueue.py 2020-02-02 01:00:00.000000000
+0100
@@ -2,6 +2,8 @@
from typing import TYPE_CHECKING, Any
+from queuelib.queue import _clear
+
if TYPE_CHECKING:
from collections.abc import Callable, Iterable
@@ -18,6 +20,9 @@
* close()
* __len__()
+ Internal queues may also implement clear(); those that do not are emptied
+ by popping.
+
The constructor receives a qfactory argument, which is a callable used to
instantiate a new (internal) queue when a new priority is allocated. The
qfactory function is called with the priority number as first and only
@@ -66,6 +71,13 @@
return None
return self.queues[self.curprio].peek()
+ def clear(self) -> None:
+ for q in self.queues.values():
+ _clear(q)
+ q.close()
+ self.queues.clear()
+ self.curprio = None
+
def close(self) -> list[int]:
active = []
for p, q in self.queues.items():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/queuelib/queue.py
new/queuelib-1.10.0/queuelib/queue.py
--- old/queuelib-1.9.0/queuelib/queue.py 2020-02-02 01:00:00.000000000
+0100
+++ new/queuelib-1.10.0/queuelib/queue.py 2020-02-02 01:00:00.000000000
+0100
@@ -11,6 +11,17 @@
from typing import Any, BinaryIO, Literal, cast
+def _clear(queue: Any) -> None:
+ """Remove every item from *queue*, popping them one by one if it does not
+ implement ``clear()``."""
+ clear = getattr(queue, "clear", None)
+ if clear is not None:
+ clear()
+ return
+ while queue.pop() is not None:
+ pass
+
+
class _BaseQueueMeta(type):
"""
Metaclass to check queue classes against the necessary interface
@@ -72,6 +83,9 @@
def peek(self) -> Any | None:
return self.q[0] if self.q else None
+ def clear(self) -> None:
+ self.q.clear()
+
def close(self) -> None:
pass
@@ -159,6 +173,17 @@
os.lseek(tfd, tfd_initial_pos, os.SEEK_SET)
return data
+ def clear(self) -> None:
+ self.headf.close()
+ self.tailf.close()
+ for chunk in Path(self.path).glob("q*"):
+ chunk.unlink()
+ self.info["size"] = 0
+ self.info["tail"] = [0, 0, 0]
+ self.info["head"] = [0, 0]
+ self.headf = self._openchunk(0, "ab+")
+ self.tailf = self._openchunk(0)
+
def close(self) -> None:
self.headf.close()
self.tailf.close()
@@ -243,6 +268,12 @@
self.f.seek(-size - self.SIZE_SIZE, os.SEEK_END)
return self.f.read(size)
+ def clear(self) -> None:
+ self.f.seek(0)
+ self.f.write(struct.pack(self.SIZE_FORMAT, 0))
+ self.f.truncate()
+ self.size = 0
+
def close(self) -> None:
if self.size:
self.f.seek(0)
@@ -261,6 +292,7 @@
_sql_push = "INSERT INTO queue (item) VALUES (?)"
_sql_pop = "SELECT id, item FROM queue ORDER BY id LIMIT 1"
_sql_del = "DELETE FROM queue WHERE id = ?"
+ _sql_clear = "DELETE FROM queue"
def __init__(self, path: str | os.PathLike[str]) -> None:
self._path = Path(path).resolve()
@@ -288,6 +320,10 @@
return cast("bytes", item)
return None
+ def clear(self) -> None:
+ with self._db as conn:
+ conn.execute(self._sql_clear)
+
def close(self) -> None:
size = len(self)
self._db.close()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/queuelib/rrqueue.py
new/queuelib-1.10.0/queuelib/rrqueue.py
--- old/queuelib-1.9.0/queuelib/rrqueue.py 2020-02-02 01:00:00.000000000
+0100
+++ new/queuelib-1.10.0/queuelib/rrqueue.py 2020-02-02 01:00:00.000000000
+0100
@@ -3,6 +3,8 @@
from collections import deque
from typing import TYPE_CHECKING, Any
+from queuelib.queue import _clear
+
if TYPE_CHECKING:
from collections.abc import Callable, Hashable, Iterable
@@ -17,6 +19,10 @@
* peek()
* close()
* __len__()
+
+ Internal queues may also implement clear(); those that do not are emptied
+ by popping.
+
The constructor receives a qfactory argument, which is a callable used to
instantiate a new (internal) queue when a new key is allocated. The
qfactory function is called with the key number as first and only argument.
@@ -53,6 +59,13 @@
return None
return self.queues[key].peek()
+ def clear(self) -> None:
+ for q in self.queues.values():
+ _clear(q)
+ q.close()
+ self.queues.clear()
+ self.key_queue.clear()
+
def pop(self) -> Any | None:
# pop until we find a valid object, closing necessary queues
while True:
@@ -70,7 +83,7 @@
else:
self.key_queue.appendleft(key)
- if m:
+ if m is not None:
return m
def close(self) -> list[Hashable]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/queuelib/tests/__init__.py
new/queuelib-1.10.0/queuelib/tests/__init__.py
--- old/queuelib-1.9.0/queuelib/tests/__init__.py 2020-02-02
01:00:00.000000000 +0100
+++ new/queuelib-1.10.0/queuelib/tests/__init__.py 2020-02-02
01:00:00.000000000 +0100
@@ -1,7 +1,32 @@
+from __future__ import annotations
+
import shutil
import tempfile
import unittest
from pathlib import Path
+from typing import Any
+
+
+class DummyQueue:
+ """Minimal queue implementation, without the optional clear() method."""
+
+ def __init__(self) -> None:
+ self.q: list[Any] = []
+
+ def push(self, obj: Any) -> None:
+ self.q.append(obj)
+
+ def pop(self) -> Any | None:
+ return self.q.pop() if self.q else None
+
+ def peek(self) -> Any | None:
+ return self.q[-1] if self.q else None
+
+ def close(self) -> None:
+ pass
+
+ def __len__(self) -> int:
+ return len(self.q)
class QueuelibTestCase(unittest.TestCase):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/queuelib/tests/test_pqueue.py
new/queuelib-1.10.0/queuelib/tests/test_pqueue.py
--- old/queuelib-1.9.0/queuelib/tests/test_pqueue.py 2020-02-02
01:00:00.000000000 +0100
+++ new/queuelib-1.10.0/queuelib/tests/test_pqueue.py 2020-02-02
01:00:00.000000000 +0100
@@ -11,7 +11,7 @@
LifoMemoryQueue,
LifoSQLiteQueue,
)
-from queuelib.tests import QueuelibTestCase, track_closed
+from queuelib.tests import DummyQueue, QueuelibTestCase, track_closed
class PQueueTestMixin:
@@ -54,6 +54,21 @@
self.q.pop()
assert sorted(self.q.close()) == [2, 3]
+ def test_clear(self):
+ self.q.clear()
+ assert len(self.q) == 0
+ self.q.push(b"a", 3)
+ self.q.push(b"b", 1)
+ iqueues = list(self.q.queues.values())
+ self.q.clear()
+ assert len(self.q) == 0
+ assert self.q.peek() is None
+ assert self.q.pop() is None
+ assert all(q.closed for q in iqueues)
+ self.q.push(b"c", 2)
+ assert self.q.pop() == b"c"
+ assert not self.q.close()
+
def test_popped_internal_queues_closed(self):
self.q.push(b"a", 3)
self.q.push(b"b", 1)
@@ -210,3 +225,14 @@
def qfactory(self, prio):
path = Path(self.qdir, str(prio))
return track_closed(LifoSQLiteQueue)(path)
+
+
+class DummyPriorityQueueTest(QueuelibTestCase):
+ def test_clear(self):
+ q = PriorityQueue(lambda prio: DummyQueue())
+ q.push(b"a", 1)
+ q.push(b"b", 2)
+ q.clear()
+ assert len(q) == 0
+ assert q.pop() is None
+ assert not q.close()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/queuelib/tests/test_queue.py
new/queuelib-1.10.0/queuelib/tests/test_queue.py
--- old/queuelib-1.9.0/queuelib/tests/test_queue.py 2020-02-02
01:00:00.000000000 +0100
+++ new/queuelib-1.10.0/queuelib/tests/test_queue.py 2020-02-02
01:00:00.000000000 +0100
@@ -1,7 +1,6 @@
from __future__ import annotations
from abc import abstractmethod
-from typing import Any
from unittest import mock
import pytest
@@ -15,27 +14,7 @@
LifoMemoryQueue,
LifoSQLiteQueue,
)
-from queuelib.tests import QueuelibTestCase
-
-
-class DummyQueue:
- def __init__(self) -> None:
- self.q: list[Any] = []
-
- def push(self, obj: Any) -> None:
- self.q.append(obj)
-
- def pop(self) -> Any | None:
- return self.q.pop() if self.q else None
-
- def peek(self) -> Any | None:
- return self.q[-1] if self.q else None
-
- def close(self) -> None:
- pass
-
- def __len__(self):
- return len(self.q)
+from queuelib.tests import DummyQueue, QueuelibTestCase
class InterfaceTest(QueuelibTestCase):
@@ -119,6 +98,20 @@
assert len(q) == 0
q.close()
+ def test_clear(self):
+ q = self.queue()
+ q.clear()
+ assert len(q) == 0
+ q.push(b"a")
+ q.push(b"b")
+ q.clear()
+ assert len(q) == 0
+ assert q.peek() is None
+ assert q.pop() is None
+ q.push(b"c")
+ assert q.pop() == b"c"
+ q.close()
+
def test_peek_one_element(self):
q = self.queue()
assert q.peek() is None
@@ -226,20 +219,24 @@
class PersistentTestMixin:
chunksize = 100000
+ # Scrapy SerializableQueue doesn't raise TypeError for non-bytes objects,
+ # so this test fails when run for it.
@pytest.mark.xfail(
reason="Reenable once Scrapy.squeues stops extending from this
testsuite"
)
def test_non_bytes_raises_typeerror(self):
q = self.queue()
- with pytest.raises(TypeError):
- q.push(0)
- with pytest.raises(TypeError):
- q.push("")
- with pytest.raises(TypeError):
- q.push(None)
- with pytest.raises(TypeError):
- q.push(lambda x: x)
- q.close()
+ try:
+ with pytest.raises(TypeError):
+ q.push(0)
+ with pytest.raises(TypeError):
+ q.push("")
+ with pytest.raises(TypeError):
+ q.push(None)
+ with pytest.raises(TypeError):
+ q.push(lambda x: x)
+ finally:
+ q.close()
def test_text_in_windows(self):
e1 = b"\r\n"
@@ -333,6 +330,14 @@
assert len(chunks) == 1
q.close()
+ def test_clear_removes_chunks(self):
+ q = self.queue()
+ for x in [b"0", b"1", b"2", b"3", b"4"]:
+ q.push(x)
+ q.clear()
+ assert list(self.qpath.glob("q*")) == [self.qpath / "q00000"]
+ q.close()
+
class ChunkSize1FifoDiskQueueTest(FifoDiskQueueTest):
chunksize = 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/queuelib-1.9.0/queuelib/tests/test_rrqueue.py
new/queuelib-1.10.0/queuelib/tests/test_rrqueue.py
--- old/queuelib-1.9.0/queuelib/tests/test_rrqueue.py 2020-02-02
01:00:00.000000000 +0100
+++ new/queuelib-1.10.0/queuelib/tests/test_rrqueue.py 2020-02-02
01:00:00.000000000 +0100
@@ -11,7 +11,7 @@
LifoSQLiteQueue,
)
from queuelib.rrqueue import RoundRobinQueue
-from queuelib.tests import QueuelibTestCase, track_closed
+from queuelib.tests import DummyQueue, QueuelibTestCase, track_closed
class RRQueueTestMixin:
@@ -47,6 +47,21 @@
assert sorted(self.q.close()) == ["1", "2", "3"]
assert all(q.closed for q in iqueues)
+ def test_clear(self):
+ self.q.clear()
+ assert len(self.q) == 0
+ self.q.push(b"a", "3")
+ self.q.push(b"b", "1")
+ iqueues = list(self.q.queues.values())
+ self.q.clear()
+ assert len(self.q) == 0
+ assert self.q.peek() is None
+ assert self.q.pop() is None
+ assert all(q.closed for q in iqueues)
+ self.q.push(b"c", "2")
+ assert self.q.pop() == b"c"
+ assert not self.q.close()
+
def test_close_return_active(self):
self.q.push(b"b", "1")
self.q.push(b"c", "2")
@@ -54,6 +69,19 @@
self.q.pop()
assert sorted(self.q.close()) == ["2", "3"]
+ def test_pop_returns_falsy_items(self):
+ self.q.push(b"", "a")
+ assert len(self.q) == 1
+ assert self.q.pop() == b""
+ assert len(self.q) == 0
+ assert self.q.pop() is None
+
+ def test_falsy_items_keep_round_robin_order(self):
+ self.q.push(b"one", "a")
+ self.q.push(b"", "b")
+ self.q.push(b"two", "c")
+ assert [self.q.pop(), self.q.pop(), self.q.pop()] == [b"one", b"",
b"two"]
+
class FifoTestMixin:
def test_push_pop_peek_key(self):
@@ -224,3 +252,14 @@
def qfactory(self, key):
path = Path(self.qdir, str(key))
return track_closed(LifoSQLiteQueue)(path)
+
+
+class DummyRRQueueTest(QueuelibTestCase):
+ def test_clear(self):
+ q = RoundRobinQueue(lambda key: DummyQueue())
+ q.push(b"a", "1")
+ q.push(b"b", "2")
+ q.clear()
+ assert len(q) == 0
+ assert q.pop() is None
+ assert not q.close()