Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-peewee for openSUSE:Factory 
checked in at 2024-09-02 13:14:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-peewee (Old)
 and      /work/SRC/openSUSE:Factory/.python-peewee.new.2698 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-peewee"

Mon Sep  2 13:14:16 2024 rev:29 rq:1198059 version:3.17.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-peewee/python-peewee.changes      
2024-06-07 15:04:47.022869894 +0200
+++ /work/SRC/openSUSE:Factory/.python-peewee.new.2698/python-peewee.changes    
2024-09-02 13:14:22.766175183 +0200
@@ -1,0 +2,19 @@
+Sat Aug 31 12:12:35 UTC 2024 - Dirk Müller <dmuel...@suse.com>
+
+- update to 3.17.6:
+  * Fix bug in recursive `model.delete_instance()` when a table
+    contains foreign-keys at multiple depths of the graph
+  * Fix regression in pool behavior on systems where
+    `time.time()` returns identical values for two connections.
+    This adds a no-op comparable sentinel to the heap to prevent
+    any recurrence of this problem.
+  * Ensure that subqueries inside `CASE` statements generate
+    correct SQL.
+  * Fix regression that broke server-side cursors with Postgres
+  * Fix to ensure compatibility with psycopg3 - the libpq
+    TransactionStatus constants are no longer available on the
+    `Connection` instance.
+  * Fix quoting issue in pwiz that could generate invalid python
+    code for double-quoted string literals used as column defaults.
+
+-------------------------------------------------------------------

Old:
----
  peewee-3.17.5.tar.gz

New:
----
  peewee-3.17.6.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-peewee.spec ++++++
--- /var/tmp/diff_new_pack.p7x7lV/_old  2024-09-02 13:14:24.310239394 +0200
+++ /var/tmp/diff_new_pack.p7x7lV/_new  2024-09-02 13:14:24.318239726 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-peewee
-Version:        3.17.5
+Version:        3.17.6
 Release:        0
 Summary:        An expressive ORM that supports multiple SQL backends
 License:        BSD-3-Clause

++++++ peewee-3.17.5.tar.gz -> peewee-3.17.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/CHANGELOG.md 
new/peewee-3.17.6/CHANGELOG.md
--- old/peewee-3.17.5/CHANGELOG.md      2024-05-10 15:42:02.000000000 +0200
+++ new/peewee-3.17.6/CHANGELOG.md      2024-07-06 19:11:45.000000000 +0200
@@ -7,7 +7,30 @@
 
 ## master
 
-[View commits](https://github.com/coleifer/peewee/compare/3.17.4...master)
+[View commits](https://github.com/coleifer/peewee/compare/3.17.6...master)
+
+## 3.17.6
+
+* Fix bug in recursive `model.delete_instance()` when a table contains
+  foreign-keys at multiple depths of the graph, #2893.
+* Fix regression in pool behavior on systems where `time.time()` returns
+  identical values for two connections. This adds a no-op comparable sentinel
+  to the heap to prevent any recurrence of this problem, #2901.
+* Ensure that subqueries inside `CASE` statements generate correct SQL.
+* Fix regression that broke server-side cursors with Postgres (introduced in
+  3.16.0).
+* Fix to ensure compatibility with psycopg3 - the libpq TransactionStatus
+  constants are no longer available on the `Connection` instance.
+* Fix quoting issue in pwiz that could generate invalid python code for
+  double-quoted string literals used as column defaults.
+
+[View commits](https://github.com/coleifer/peewee/compare/3.17.5...3.17.6)
+
+## 3.17.5
+
+This release fixes a build system problem in Python 3.12, #2891.
+
+[View commits](https://github.com/coleifer/peewee/compare/3.17.4...3.17.5)
 
 ## 3.17.4
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/docs/peewee/api.rst 
new/peewee-3.17.6/docs/peewee/api.rst
--- old/peewee-3.17.5/docs/peewee/api.rst       2024-05-10 15:42:02.000000000 
+0200
+++ new/peewee-3.17.6/docs/peewee/api.rst       2024-07-06 19:11:45.000000000 
+0200
@@ -3982,7 +3982,37 @@
 
 .. py:class:: SubclassAwareMetadata
 
-    Metadata subclass that tracks :py:class:`Model` subclasses.
+    Metadata subclass that tracks :py:class:`Model` subclasses. Useful for
+    when you need to track all models in a project.
+
+    Example:
+
+    .. code-block:: python
+
+        from peewee import SubclassAwareMetadata
+
+        class Base(Model):
+            class Meta:
+                database = db
+                model_metadata_class = SubclassAwareMetadata
+
+        # Create 3 model classes that inherit from Base.
+        class A(Base): pass
+        class B(Base): pass
+        class C(Base): pass
+
+        # Now let's make a helper for changing the `schema` for each Model.
+        def change_schema(schema):
+            def _update(model):
+                model._meta.schema = schema
+            return _update
+
+        # Set all models to use "schema1", e.g. "schema1.a", "schema1.b", etc.
+        # Will apply the function to every subclass of Base.
+        Base._meta.map_models(change_schema('schema1'))
+
+        # Set all models to use "schema2", e.g. "schema2.a", "schema2.b", etc.
+        Base._meta.map_models(change_schema('schema2'))
 
     .. py:method:: map_models(fn)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/docs/peewee/query_operators.rst 
new/peewee-3.17.6/docs/peewee/query_operators.rst
--- old/peewee-3.17.5/docs/peewee/query_operators.rst   2024-05-10 
15:42:02.000000000 +0200
+++ new/peewee-3.17.6/docs/peewee/query_operators.rst   2024-07-06 
19:11:45.000000000 +0200
@@ -117,7 +117,7 @@
     * Use ``|`` instead of ``or``
     * Use ``~`` instead of ``not``
     * Use ``.is_null()`` instead of ``is None`` or ``== None``.
-    * Use ``== `` and ``!=`` for comparing against ``True`` and ``False``, or
+    * Use ``==`` and ``!=`` for comparing against ``True`` and ``False``, or
       you may use the implicit value of the expression.
     * **Don't forget to wrap your comparisons in parentheses when using 
logical operators.**
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/peewee.py new/peewee-3.17.6/peewee.py
--- old/peewee-3.17.5/peewee.py 2024-05-10 15:42:02.000000000 +0200
+++ new/peewee-3.17.6/peewee.py 2024-07-06 19:11:45.000000000 +0200
@@ -74,7 +74,7 @@
         mysql = None
 
 
-__version__ = '3.17.5'
+__version__ = '3.17.6'
 __all__ = [
     'AnyField',
     'AsIs',
@@ -1827,6 +1827,16 @@
         return ctx.literal(self.window._alias or 'w')
 
 
+class _InFunction(Node):
+    def __init__(self, node, in_function=True):
+        self.node = node
+        self.in_function = in_function
+
+    def __sql__(self, ctx):
+        with ctx(in_function=self.in_function):
+            return ctx.sql(self.node)
+
+
 class Case(ColumnBase):
     def __init__(self, predicate, expression_tuples, default=None):
         self.predicate = predicate
@@ -1838,9 +1848,10 @@
         if self.predicate is not None:
             clauses.append(self.predicate)
         for expr, value in self.expression_tuples:
-            clauses.extend((SQL('WHEN'), expr, SQL('THEN'), value))
+            clauses.extend((SQL('WHEN'), expr,
+                            SQL('THEN'), _InFunction(value)))
         if self.default is not None:
-            clauses.extend((SQL('ELSE'), self.default))
+            clauses.extend((SQL('ELSE'), _InFunction(self.default)))
         clauses.append(SQL('END'))
         with ctx(in_function=False):
             return ctx.sql(NodeList(clauses))
@@ -6956,9 +6967,10 @@
     def dirty_fields(self):
         return [f for f in self._meta.sorted_fields if f.name in self._dirty]
 
-    def dependencies(self, search_nullable=False):
+    def dependencies(self, search_nullable=True):
         model_class = type(self)
         stack = [(type(self), None)]
+        queries = {}
         seen = set()
 
         while stack:
@@ -6974,13 +6986,16 @@
                 subquery = (rel_model.select(rel_model._meta.primary_key)
                             .where(node))
                 if not fk.null or search_nullable:
+                    queries.setdefault(rel_model, []).append((node, fk))
                     stack.append((rel_model, subquery))
-                yield (node, fk)
+
+        for m in reversed(sort_models(seen)):
+            for sq, q in queries.get(m, ()):
+                yield sq, q
 
     def delete_instance(self, recursive=False, delete_nullable=False):
         if recursive:
-            dependencies = self.dependencies(delete_nullable)
-            for query, fk in reversed(list(dependencies)):
+            for query, fk in self.dependencies():
                 model = fk.model
                 if fk.null and not delete_nullable:
                     model.update(**{fk.name: None}).where(query).execute()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/playhouse/pool.py 
new/peewee-3.17.6/playhouse/pool.py
--- old/peewee-3.17.5/playhouse/pool.py 2024-05-10 15:42:02.000000000 +0200
+++ new/peewee-3.17.6/playhouse/pool.py 2024-07-06 19:11:45.000000000 +0200
@@ -34,7 +34,6 @@
 import functools
 import heapq
 import logging
-import random
 import threading
 import time
 from collections import namedtuple
@@ -48,6 +47,10 @@
     TRANSACTION_STATUS_IDLE = \
             TRANSACTION_STATUS_INERROR = \
             TRANSACTION_STATUS_UNKNOWN = None
+try:
+    from psycopg.pq import TransactionStatus
+except ImportError:
+    pass
 
 from peewee import MySQLDatabase
 from peewee import PostgresqlDatabase
@@ -68,6 +71,10 @@
 PoolConnection = namedtuple('PoolConnection', ('timestamp', 'connection',
                                                'checked_out'))
 
+class _sentinel(object):
+    def __lt__(self, other):
+        return True
+
 
 def locked(fn):
     @functools.wraps(fn)
@@ -136,7 +143,8 @@
         while True:
             try:
                 # Remove the oldest connection from the heap.
-                ts, conn = heapq.heappop(self._connections)
+                ts, _, c_conn = heapq.heappop(self._connections)
+                conn = c_conn
                 key = self.conn_key(conn)
             except IndexError:
                 ts = conn = None
@@ -198,7 +206,8 @@
                 super(PooledDatabase, self)._close(conn)
             elif self._can_reuse(conn):
                 logger.debug('Returning %s to pool.', key)
-                heapq.heappush(self._connections, (pool_conn.timestamp, conn))
+                heapq.heappush(self._connections,
+                               (pool_conn.timestamp, _sentinel(), conn))
             else:
                 logger.debug('Closed %s.', key)
 
@@ -224,7 +233,7 @@
     @locked
     def close_idle(self):
         # Close any open connections that are not currently in-use.
-        for _, conn in self._connections:
+        for _, _, conn in self._connections:
             self._close(conn, close_conn=True)
         self._connections = []
 
@@ -249,7 +258,7 @@
         # Close all connections -- available and in-use. Warning: may break any
         # active connections used by other threads.
         self.close()
-        for _, conn in self._connections:
+        for _, _, conn in self._connections:
             self._close(conn, close_conn=True)
         for pool_conn in self._in_use.values():
             self._close(pool_conn.connection, close_conn=True)
@@ -317,9 +326,9 @@
                 return True
 
             txn_status = conn.pgconn.transaction_status
-            if txn_status == conn.TransactionStatus.UNKNOWN:
+            if txn_status == TransactionStatus.UNKNOWN:
                 return True
-            elif txn_status != conn.TransactionStatus.IDLE:
+            elif txn_status != TransactionStatus.IDLE:
                 conn.rollback()
             return False
 
@@ -328,11 +337,11 @@
             # Do not return connection in an error state, as subsequent queries
             # will all fail. If the status is unknown then we lost the 
connection
             # to the server and the connection should not be re-used.
-            if txn_status == conn.TransactionStatus.UNKNOWN:
+            if txn_status == TransactionStatus.UNKNOWN:
                 return False
-            elif txn_status == conn.TransactionStatus.INERROR:
+            elif txn_status == TransactionStatus.INERROR:
                 conn.reset()
-            elif txn_status != conn.TransactionStatus.IDLE:
+            elif txn_status != TransactionStatus.IDLE:
                 conn.rollback()
             return True
 except ImportError:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/playhouse/postgres_ext.py 
new/peewee-3.17.6/playhouse/postgres_ext.py
--- old/peewee-3.17.5/playhouse/postgres_ext.py 2024-05-10 15:42:02.000000000 
+0200
+++ new/peewee-3.17.6/playhouse/postgres_ext.py 2024-07-06 19:11:45.000000000 
+0200
@@ -13,6 +13,7 @@
 from peewee import Node
 from peewee import NodeList
 from peewee import __deprecated__
+from peewee import __exception_wrapper__
 
 try:
     from psycopg2cffi import compat
@@ -394,6 +395,13 @@
         self.exhausted = False
         self.iterable = self.row_gen()
 
+    def __del__(self):
+        if self.cursor and not self.cursor.closed:
+            try:
+                self.cursor.close()
+            except Exception:
+                pass
+
     @property
     def description(self):
         return self.cursor.description
@@ -402,12 +410,15 @@
         self.cursor.close()
 
     def row_gen(self):
-        while True:
-            rows = self.cursor.fetchmany(self.array_size)
-            if not rows:
-                return
-            for row in rows:
-                yield row
+        try:
+            while True:
+                rows = self.cursor.fetchmany(self.array_size)
+                if not rows:
+                    return
+                for row in rows:
+                    yield row
+        finally:
+            self.close()
 
     def fetchone(self):
         if self.exhausted:
@@ -443,10 +454,9 @@
 def ServerSide(query, database=None, array_size=None):
     if database is None:
         database = query._database
-    with database.transaction():
-        server_side_query = ServerSideQuery(query, array_size=array_size)
-        for row in server_side_query:
-            yield row
+    server_side_query = ServerSideQuery(query, array_size=array_size)
+    for row in server_side_query:
+        yield row
 
 
 class _empty_object(object):
@@ -477,7 +487,8 @@
             else:
                 raise InterfaceError('Error, database connection not opened.')
         if named_cursor:
-            curs = self._state.conn.cursor(name=str(uuid.uuid1()))
+            curs = self._state.conn.cursor(name=str(uuid.uuid1()),
+                                           withhold=True)
             return curs
         return self._state.conn.cursor()
 
@@ -489,7 +500,16 @@
         sql, params = ctx.sql(query).query()
         named_cursor = named_cursor or (self._server_side_cursors and
                                         sql[:6].lower() == 'select')
-        cursor = self.execute_sql(sql, params)
+        cursor = self.execute_sql(sql, params, named_cursor=named_cursor)
         if named_cursor:
             cursor = FetchManyCursor(cursor, array_size)
         return cursor
+
+    def execute_sql(self, sql, params=None, commit=None, named_cursor=None):
+        if commit is not None:
+            __deprecated__('"commit" has been deprecated and is a no-op.')
+        logger.debug((sql, params))
+        with __exception_wrapper__:
+            cursor = self.cursor(named_cursor=named_cursor)
+            cursor.execute(sql, params or ())
+        return cursor
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/playhouse/psycopg3_ext.py 
new/peewee-3.17.6/playhouse/psycopg3_ext.py
--- old/peewee-3.17.5/playhouse/psycopg3_ext.py 2024-05-10 15:42:02.000000000 
+0200
+++ new/peewee-3.17.6/playhouse/psycopg3_ext.py 2024-07-06 19:11:45.000000000 
+0200
@@ -16,6 +16,7 @@
 try:
     import psycopg
     from psycopg.types.json import Jsonb
+    from psycopg.pq import TransactionStatus
 except ImportError:
     psycopg = Jsonb = None
 
@@ -160,7 +161,7 @@
         # connection. If the connection is in an error state or the connection
         # is otherwise unusable, return False.
         conn = self._state.conn
-        return conn.pgconn.transaction_status < conn.TransactionStatus.INERROR
+        return conn.pgconn.transaction_status < TransactionStatus.INERROR
 
     def extract_date(self, date_part, date_field):
         return fn.EXTRACT(NodeList((SQL(date_part), SQL('FROM'), date_field)))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/playhouse/reflection.py 
new/peewee-3.17.6/playhouse/reflection.py
--- old/peewee-3.17.5/playhouse/reflection.py   2024-05-10 15:42:02.000000000 
+0200
+++ new/peewee-3.17.6/playhouse/reflection.py   2024-07-06 19:11:45.000000000 
+0200
@@ -92,7 +92,7 @@
         if self.primary_key and not issubclass(self.field_class, AutoField):
             params['primary_key'] = True
         if self.default is not None:
-            params['constraints'] = '[SQL("DEFAULT %s")]' % self.default
+            params['constraints'] = '[SQL(\'DEFAULT %s\')]' % self.default
 
         # Handle ForeignKeyField-specific attributes.
         if self.is_foreign_key():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/tests/base.py 
new/peewee-3.17.6/tests/base.py
--- old/peewee-3.17.5/tests/base.py     2024-05-10 15:42:02.000000000 +0200
+++ new/peewee-3.17.6/tests/base.py     2024-07-06 19:11:45.000000000 +0200
@@ -179,6 +179,12 @@
         if params is not None:
             self.assertEqual(qparams, params)
 
+    def assertHistory(self, n, expected):
+        queries = [logrecord.msg for logrecord in self._qh.queries[-n:]]
+        queries = [(sql.replace('%s', '?').replace('`', '"'), params)
+                   for sql, params in queries]
+        self.assertEqual(queries, expected)
+
     @property
     def history(self):
         return self._qh.queries
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/tests/db_tests.py 
new/peewee-3.17.6/tests/db_tests.py
--- old/peewee-3.17.5/tests/db_tests.py 2024-05-10 15:42:02.000000000 +0200
+++ new/peewee-3.17.6/tests/db_tests.py 2024-07-06 19:11:45.000000000 +0200
@@ -700,6 +700,35 @@
             sorted_models = sort_models(list_of_models)
             self.assertEqual(sorted_models, models)
 
+    def test_sort_models_multi_fk(self):
+        class Inventory(Model):
+            pass
+        class Sheet(Model):
+            inventory = ForeignKeyField(Inventory)
+        class Program(Model):
+            inventory = ForeignKeyField(Inventory)
+        class ProgramSheet(Model):
+            program = ForeignKeyField(Program)
+            sheet = ForeignKeyField(Sheet)
+        class ProgramPart(Model):
+            program_sheet = ForeignKeyField(ProgramSheet)
+        class Offal(Model):
+            program_sheet = ForeignKeyField(ProgramSheet)
+            sheet = ForeignKeyField(Sheet)
+
+        M = [Inventory, Sheet, Program, ProgramSheet, ProgramPart, Offal]
+        sorted_models = sort_models(M)
+        self.assertEqual(sorted_models, [
+            Inventory,
+            Program,
+            Sheet,
+            ProgramSheet,
+            Offal,
+            ProgramPart,
+        ])
+        for list_of_models in permutations(M):
+            self.assertEqual(sort_models(list_of_models), sorted_models)
+
 
 class TestDBProxy(BaseTestCase):
     def test_proxy_context_manager(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/tests/models.py 
new/peewee-3.17.6/tests/models.py
--- old/peewee-3.17.5/tests/models.py   2024-05-10 15:42:02.000000000 +0200
+++ new/peewee-3.17.6/tests/models.py   2024-07-06 19:11:45.000000000 +0200
@@ -1595,22 +1595,24 @@
 
     def test_delete_instance_recursive(self):
         huey = User.get(User.username == 'huey')
+        a = []
+        for d in huey.dependencies():
+            a.append(d)
         with self.assertQueryCount(5):
             huey.delete_instance(recursive=True)
 
-        queries = [logrecord.msg for logrecord in self._qh.queries[-5:]]
-        self.assertEqual(sorted(queries), [
+        self.assertHistory(5, [
+            ('DELETE FROM "favorite" WHERE ("favorite"."user_id" = ?)',
+             [huey.id]),
             ('DELETE FROM "favorite" WHERE ('
              '"favorite"."tweet_id" IN ('
              'SELECT "t1"."id" FROM "tweet" AS "t1" WHERE ('
              '"t1"."user_id" = ?)))', [huey.id]),
-            ('DELETE FROM "favorite" WHERE ("favorite"."user_id" = ?)',
-             [huey.id]),
             ('DELETE FROM "tweet" WHERE ("tweet"."user_id" = ?)', [huey.id]),
-            ('DELETE FROM "users" WHERE ("users"."id" = ?)', [huey.id]),
             ('UPDATE "account" SET "user_id" = ? '
              'WHERE ("account"."user_id" = ?)',
              [None, huey.id]),
+            ('DELETE FROM "users" WHERE ("users"."id" = ?)', [huey.id]),
         ])
 
         # Only one user left.
@@ -1638,17 +1640,16 @@
             huey.delete_instance(recursive=True, delete_nullable=True)
 
         # Get the last 5 delete queries.
-        queries = [logrecord.msg for logrecord in self._qh.queries[-5:]]
-        self.assertEqual(sorted(queries), [
-            ('DELETE FROM "account" WHERE ("account"."user_id" = ?)',
+        self.assertHistory(5, [
+            ('DELETE FROM "favorite" WHERE ("favorite"."user_id" = ?)',
              [huey.id]),
             ('DELETE FROM "favorite" WHERE ('
              '"favorite"."tweet_id" IN ('
              'SELECT "t1"."id" FROM "tweet" AS "t1" WHERE ('
              '"t1"."user_id" = ?)))', [huey.id]),
-            ('DELETE FROM "favorite" WHERE ("favorite"."user_id" = ?)',
-             [huey.id]),
             ('DELETE FROM "tweet" WHERE ("tweet"."user_id" = ?)', [huey.id]),
+            ('DELETE FROM "account" WHERE ("account"."user_id" = ?)',
+             [huey.id]),
             ('DELETE FROM "users" WHERE ("users"."id" = ?)', [huey.id]),
         ])
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/tests/pool.py 
new/peewee-3.17.6/tests/pool.py
--- old/peewee-3.17.5/tests/pool.py     2024-05-10 15:42:02.000000000 +0200
+++ new/peewee-3.17.6/tests/pool.py     2024-07-06 19:11:45.000000000 +0200
@@ -112,7 +112,7 @@
 
         self.assertEqual(db.counter, 5)
         self.assertEqual(
-            sorted([conn for _, conn in db._connections]),
+            sorted([conn for _, _, conn in db._connections]),
             [1, 2, 3, 4, 5])  # All 5 are ready to be re-used.
         self.assertEqual(db._in_use, {})
 
@@ -184,9 +184,9 @@
         db = FakePooledDatabase('testing', counter=3)
 
         now = time.time()
-        heapq.heappush(db._connections, (now - 10, 3))
-        heapq.heappush(db._connections, (now - 5, 2))
-        heapq.heappush(db._connections, (now - 1, 1))
+        heapq.heappush(db._connections, (now - 10, None, 3))
+        heapq.heappush(db._connections, (now - 5, None, 2))
+        heapq.heappush(db._connections, (now - 1, None, 1))
 
         self.assertEqual(db.connection(), 3)
         self.assertTrue(3 in db._in_use)
@@ -218,9 +218,9 @@
         db = FakePooledDatabase('testing', counter=3)
 
         now = time.time()
-        heapq.heappush(db._connections, (now - 10, 3))
-        heapq.heappush(db._connections, (now - 5, 2))
-        heapq.heappush(db._connections, (now - 1, 1))
+        heapq.heappush(db._connections, (now - 10, None, 3))
+        heapq.heappush(db._connections, (now - 5, None, 2))
+        heapq.heappush(db._connections, (now - 1, None, 1))
         self.assertEqual(db.connection(), 3)
         self.assertTrue(3 in db._in_use)
 
@@ -234,10 +234,10 @@
         now = time.time()
         db = FakePooledDatabase('testing', stale_timeout=10)
         conns = [
-            (now - 20, 1),
-            (now - 15, 2),
-            (now - 5, 3),
-            (now, 4),
+            (now - 20, None, 1),
+            (now - 15, None, 2),
+            (now - 5, None, 3),
+            (now, None, 4),
         ]
         for ts_conn in conns:
             heapq.heappush(db._connections, ts_conn)
@@ -245,7 +245,7 @@
         self.assertEqual(db.connection(), 3)
         self.assertEqual(len(db._in_use), 1)
         self.assertTrue(3 in db._in_use)
-        self.assertEqual(db._connections, [(now, 4)])
+        self.assertEqual(db._connections, [(now, None, 4)])
 
     def test_connect_cascade(self):
         now = time.time()
@@ -256,10 +256,10 @@
         db = ClosedPooledDatabase('testing', stale_timeout=10)
 
         conns = [
-            (now - 15, 1),  # Skipped due to being stale.
-            (now - 5, 2),  # Will appear closed.
-            (now - 3, 3),
-            (now, 4),  # Will appear closed.
+            (now - 15, None, 1),  # Skipped due to being stale.
+            (now - 5, None, 2),  # Will appear closed.
+            (now - 3, None, 3),
+            (now, None, 4),  # Will appear closed.
         ]
         db.counter = 4  # The next connection we create will have id=5.
         for ts_conn in conns:
@@ -272,7 +272,7 @@
         pool_conn = db._in_use[3]
         self.assertEqual(pool_conn.timestamp, now - 3)
         self.assertEqual(pool_conn.connection, 3)
-        self.assertEqual(db._connections, [(now, 4)])
+        self.assertEqual(db._connections, [(now, None, 4)])
 
         # Since conn 4 is closed, we will open a new conn.
         db._state.closed = True  # Pretend we're in a different thread.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/tests/postgres.py 
new/peewee-3.17.6/tests/postgres.py
--- old/peewee-3.17.5/tests/postgres.py 2024-05-10 15:42:02.000000000 +0200
+++ new/peewee-3.17.6/tests/postgres.py 2024-07-06 19:11:45.000000000 +0200
@@ -815,6 +815,16 @@
         ss_query = ServerSide(query.where(SQL('1 = 0')))
         self.assertEqual(list(ss_query), [])
 
+    def test_lower_level_apis(self):
+        query = Register.select(Register.value).order_by(Register.value)
+        ssq = ServerSideQuery(query, array_size=10)
+        curs_wrapper = ssq._execute(self.database)
+        curs = curs_wrapper.cursor
+        self.assertTrue(isinstance(curs, FetchManyCursor))
+        self.assertEqual(curs.fetchone(), (0,))
+        self.assertEqual(curs.fetchone(), (1,))
+        curs.close()
+
 
 class KX(TestModel):
     key = CharField(unique=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/tests/regressions.py 
new/peewee-3.17.6/tests/regressions.py
--- old/peewee-3.17.5/tests/regressions.py      2024-05-10 15:42:02.000000000 
+0200
+++ new/peewee-3.17.6/tests/regressions.py      2024-07-06 19:11:45.000000000 
+0200
@@ -138,8 +138,7 @@
         with self.assertQueryCount(5):
             a2.delete_instance(recursive=True)
 
-        queries = [logrecord.msg for logrecord in self._qh.queries[-5:]]
-        self.assertEqual(sorted(queries, reverse=True), [
+        self.assertHistory(5, [
             ('DELETE FROM "di_d" WHERE ("di_d"."c_id" IN ('
              'SELECT "t1"."id" FROM "di_c" AS "t1" WHERE ("t1"."b_id" IN ('
              'SELECT "t2"."id" FROM "di_b" AS "t2" WHERE ("t2"."a_id" = ?)'
@@ -1823,3 +1822,69 @@
         case = Case(None, [(Sample.id.in_(subq), Sample.value)], 0)
         q = Sample.select(fn.SUM(case))
         self.assertEqual(q.scalar(), 4.0)
+
+
+class I(TestModel):
+    name = TextField()
+class S(TestModel):
+    i = ForeignKeyField(I)
+class P(TestModel):
+    i = ForeignKeyField(I)
+class PS(TestModel):
+    p = ForeignKeyField(P)
+    s = ForeignKeyField(S)
+class PP(TestModel):
+    ps = ForeignKeyField(PS)
+class O(TestModel):
+    ps = ForeignKeyField(PS)
+    s = ForeignKeyField(S)
+class OX(TestModel):
+    o = ForeignKeyField(O, null=True)
+
+class TestDeleteInstanceDFS(ModelTestCase):
+    requires = [I, S, P, PS, PP, O, OX]
+
+    def test_delete_instance_dfs(self):
+        i1, i2 = [I.create(name=n) for n in ('i1', 'i2')]
+        for i in (i1, i2):
+            s = S.create(i=i)
+            p = P.create(i=i)
+            ps = PS.create(p=p, s=s)
+            pp = PP.create(ps=ps)
+            o = O.create(ps=ps, s=s)
+            ox = OX.create(o=o)
+
+        with self.assertQueryCount(9):
+            i1.delete_instance(recursive=True)
+
+        self.assertHistory(9, [
+            ('DELETE FROM "pp" WHERE ('
+             '"pp"."ps_id" IN (SELECT "t1"."id" FROM "ps" AS "t1" WHERE ('
+             '"t1"."p_id" IN (SELECT "t2"."id" FROM "p" AS "t2" WHERE ('
+             '"t2"."i_id" = ?)))))', [i1.id]),
+            ('UPDATE "ox" SET "o_id" = ? WHERE ('
+             '"ox"."o_id" IN (SELECT "t1"."id" FROM "o" AS "t1" WHERE ('
+             '"t1"."ps_id" IN (SELECT "t2"."id" FROM "ps" AS "t2" WHERE ('
+             '"t2"."p_id" IN (SELECT "t3"."id" FROM "p" AS "t3" WHERE ('
+             '"t3"."i_id" = ?)))))))', [None, i1.id]),
+            ('DELETE FROM "o" WHERE ('
+             '"o"."ps_id" IN (SELECT "t1"."id" FROM "ps" AS "t1" WHERE ('
+             '"t1"."p_id" IN (SELECT "t2"."id" FROM "p" AS "t2" WHERE ('
+             '"t2"."i_id" = ?)))))', [i1.id]),
+            ('DELETE FROM "o" WHERE ('
+             '"o"."s_id" IN (SELECT "t1"."id" FROM "s" AS "t1" WHERE ('
+             '"t1"."i_id" = ?)))', [i1.id]),
+            ('DELETE FROM "ps" WHERE ('
+             '"ps"."p_id" IN (SELECT "t1"."id" FROM "p" AS "t1" WHERE ('
+             '"t1"."i_id" = ?)))', [i1.id]),
+            ('DELETE FROM "ps" WHERE ('
+             '"ps"."s_id" IN (SELECT "t1"."id" FROM "s" AS "t1" WHERE ('
+             '"t1"."i_id" = ?)))', [i1.id]),
+            ('DELETE FROM "s" WHERE ("s"."i_id" = ?)', [i1.id]),
+            ('DELETE FROM "p" WHERE ("p"."i_id" = ?)', [i1.id]),
+            ('DELETE FROM "i" WHERE ("i"."id" = ?)', [i1.id]),
+        ])
+
+        counts = {OX: 2}
+        for m in self.requires:
+            self.assertEqual(m.select().count(), counts.get(m, 1))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/tests/sql.py 
new/peewee-3.17.6/tests/sql.py
--- old/peewee-3.17.5/tests/sql.py      2024-05-10 15:42:02.000000000 +0200
+++ new/peewee-3.17.6/tests/sql.py      2024-07-06 19:11:45.000000000 +0200
@@ -1802,6 +1802,20 @@
             'CASE WHEN ("t1"."id" IN (SELECT "t1"."id" FROM "n" AS "t1")) '
             'THEN ? ELSE ? END) FROM "n" AS "t1"'), [1, 0])
 
+        case = Case(None, [
+            (Name.id < 5, Name.select(fn.SUM(Name.id))),
+            (Name.id > 5, Name.select(fn.COUNT(Name.name)).distinct())],
+            Name.select(fn.MAX(Name.id)))
+        q = Name.select(Name.name, case.alias('magic'))
+        self.assertSQL(q, (
+            'SELECT "t1"."name", CASE '
+            'WHEN ("t1"."id" < ?) '
+            'THEN (SELECT SUM("t1"."id") FROM "n" AS "t1") '
+            'WHEN ("t1"."id" > ?) '
+            'THEN (SELECT DISTINCT COUNT("t1"."name") FROM "n" AS "t1") '
+            'ELSE (SELECT MAX("t1"."id") FROM "n" AS "t1") END AS "magic" '
+            'FROM "n" AS "t1"'), [5, 5])
+
 
 
 class TestSelectFeatures(BaseTestCase):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/peewee-3.17.5/tests/sqlcipher_ext.py 
new/peewee-3.17.6/tests/sqlcipher_ext.py
--- old/peewee-3.17.5/tests/sqlcipher_ext.py    2024-05-10 15:42:02.000000000 
+0200
+++ new/peewee-3.17.6/tests/sqlcipher_ext.py    2024-07-06 19:11:45.000000000 
+0200
@@ -11,7 +11,10 @@
 
 
 PASSPHRASE = 'testing sqlcipher'
-PRAGMAS = {'kdf_iter': 10}  # Much faster for testing. Totally unsafe.
+PRAGMAS = {
+    'kdf_iter': 10,   # Much faster for testing. Totally unsafe.
+    'cipher_log_level': 'none',
+}
 db = SqlCipherDatabase('peewee_test.dbc', passphrase=PASSPHRASE,
                        pragmas=PRAGMAS)
 ext_db = SqlCipherExtDatabase('peewee_test.dbx', passphrase=PASSPHRASE,

Reply via email to