]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
test: ignore error looking for leaks
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 13 Dec 2022 03:05:39 +0000 (03:05 +0000)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 13 Dec 2022 11:20:24 +0000 (11:20 +0000)
The leaks counter frequently reports a leak between run 1 and 2 of the
tests. It turns out to be a Decimal Context whose items() method reports
no content. So the problem is related to Python, not psycopg, and it is
not an unbound leak.

Can't reproduce it in CI, but it happens on my laptop, since switching
to Ubuntu 22.04 with Python 3.10.

tests/crdb/test_copy.py
tests/crdb/test_copy_async.py
tests/test_client_cursor.py
tests/test_client_cursor_async.py
tests/test_copy.py
tests/test_copy_async.py
tests/test_cursor.py
tests/test_cursor_async.py
tests/utils.py

index 21eb78b602cb02d548a344d6f1927f0a37e2dd0d..b7d26aa516c07aa30ac10111732dacf92cf0215d 100644 (file)
@@ -1,4 +1,3 @@
-import gc
 import pytest
 import string
 from random import randrange, choice
@@ -8,7 +7,7 @@ from psycopg.pq import Format
 from psycopg.adapt import PyFormat
 from psycopg.types.numeric import Int4
 
-from ..utils import eur, gc_collect
+from ..utils import eur, gc_collect, gc_count
 from ..test_copy import sample_text, sample_binary  # noqa
 from ..test_copy import ensure_table, sample_records
 from ..test_copy import sample_tabledef as sample_tabledef_pg
@@ -225,7 +224,7 @@ def test_copy_from_leaks(conn_cls, dsn, faker, fmt, set_types):
     for i in range(3):
         work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
 
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
 
index 7642b56354f58bafa1bd7d5279f028eeceaf11da..d5fbf50d0b35c20ed57c553cceac1ccf52314ee9 100644 (file)
@@ -1,4 +1,3 @@
-import gc
 import pytest
 import string
 from random import randrange, choice
@@ -8,7 +7,7 @@ from psycopg import sql, errors as e
 from psycopg.adapt import PyFormat
 from psycopg.types.numeric import Int4
 
-from ..utils import eur, gc_collect
+from ..utils import eur, gc_collect, gc_count
 from ..test_copy import sample_text, sample_binary  # noqa
 from ..test_copy import sample_records
 from ..test_copy_async import ensure_table
@@ -231,6 +230,6 @@ async def test_copy_from_leaks(aconn_cls, dsn, faker, fmt, set_types):
     for i in range(3):
         await work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
 
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
index 21fea8c4ffd61f6dfe58aa6a0ffa7169bcd996d8..b3556047410114404eb59679342edbd7258b65c1 100644 (file)
@@ -1,4 +1,3 @@
-import gc
 import pickle
 import weakref
 import datetime as dt
@@ -11,7 +10,7 @@ from psycopg import sql, rows
 from psycopg.adapt import PyFormat
 from psycopg.postgres import types as builtins
 
-from .utils import gc_collect
+from .utils import gc_collect, gc_count
 from .test_cursor import my_row_factory
 from .fix_crdb import is_crdb, crdb_encoding, crdb_time_precision
 
@@ -806,7 +805,7 @@ def test_leak(conn_cls, dsn, faker, fetch, row_factory):
     for i in range(3):
         work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
 
 
index 63e9c3cc9acbe627e34b8ade05ee52504d51c47b..0cf8ec6494a09bd4526b61c28af10c15c3c1c4f2 100644 (file)
@@ -1,4 +1,3 @@
-import gc
 import pytest
 import weakref
 import datetime as dt
@@ -8,7 +7,7 @@ import psycopg
 from psycopg import sql, rows
 from psycopg.adapt import PyFormat
 
-from .utils import alist, gc_collect
+from .utils import alist, gc_collect, gc_count
 from .test_cursor import my_row_factory
 from .test_cursor import execmany, _execmany  # noqa: F401
 from .fix_crdb import crdb_encoding
@@ -677,7 +676,7 @@ async def test_leak(aconn_cls, dsn, faker, fetch, row_factory):
     for i in range(3):
         await work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
 
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
 
index 7844c3c4ca608bb4f8b09e26819c1189f6c31485..74e190fceae42e70d1223f6737956cd8d48b0cc7 100644 (file)
@@ -1,4 +1,3 @@
-import gc
 import string
 import struct
 import hashlib
@@ -19,7 +18,7 @@ from psycopg.types import TypeInfo
 from psycopg.types.hstore import register_hstore
 from psycopg.types.numeric import Int4
 
-from .utils import eur, gc_collect
+from .utils import eur, gc_collect, gc_count
 
 pytestmark = pytest.mark.crdb_skip("copy")
 
@@ -727,7 +726,7 @@ def test_copy_to_leaks(conn_cls, dsn, faker, fmt, set_types, method):
     for i in range(3):
         work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
 
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
 
@@ -770,7 +769,7 @@ def test_copy_from_leaks(conn_cls, dsn, faker, fmt, set_types):
     for i in range(3):
         work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
 
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
 
index 24aa9cabfa328ef9eeafc46fe9fa061600755b4b..9b926a21322d053ca669f54fb7d4cc6938976599 100644 (file)
@@ -1,4 +1,3 @@
-import gc
 import string
 import hashlib
 from io import BytesIO, StringIO
@@ -19,7 +18,7 @@ from psycopg.adapt import PyFormat
 from psycopg.types.hstore import register_hstore
 from psycopg.types.numeric import Int4
 
-from .utils import alist, eur, gc_collect
+from .utils import alist, eur, gc_collect, gc_count
 from .test_copy import sample_text, sample_binary, sample_binary_rows  # noqa
 from .test_copy import sample_values, sample_records, sample_tabledef
 from .test_copy import py_to_raw, special_chars
@@ -734,7 +733,7 @@ async def test_copy_to_leaks(aconn_cls, dsn, faker, fmt, set_types, method):
     for i in range(3):
         await work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
 
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
 
@@ -777,7 +776,7 @@ async def test_copy_from_leaks(aconn_cls, dsn, faker, fmt, set_types):
     for i in range(3):
         await work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
 
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
 
index 8b044944a0ecc0d9def9d24023f037a5262ba191..a667f4fb32d917e0a9537808e0fbc0acf9e3341d 100644 (file)
@@ -1,4 +1,3 @@
-import gc
 import pickle
 import weakref
 import datetime as dt
@@ -13,7 +12,7 @@ from psycopg.adapt import PyFormat
 from psycopg.postgres import types as builtins
 from psycopg.rows import RowMaker
 
-from .utils import gc_collect
+from .utils import gc_collect, gc_count
 from .fix_crdb import is_crdb, crdb_encoding, crdb_time_precision
 
 
@@ -925,7 +924,7 @@ def test_leak(conn_cls, dsn, faker, fmt, fmt_out, fetch, row_factory):
     for i in range(3):
         work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
 
 
index 84b57226037490f8b4c0c523047dc75c0e8dbb19..ac3fdeb2cb9903ec36f183f042c73c381e6f14bb 100644 (file)
@@ -1,4 +1,3 @@
-import gc
 import pytest
 import weakref
 import datetime as dt
@@ -8,7 +7,7 @@ import psycopg
 from psycopg import pq, sql, rows
 from psycopg.adapt import PyFormat
 
-from .utils import gc_collect
+from .utils import gc_collect, gc_count
 from .test_cursor import my_row_factory
 from .test_cursor import execmany, _execmany  # noqa: F401
 from .fix_crdb import crdb_encoding
@@ -798,6 +797,6 @@ async def test_leak(aconn_cls, dsn, faker, fmt, fmt_out, fetch, row_factory):
     for i in range(3):
         await work()
         gc_collect()
-        n.append(len(gc.get_objects()))
+        n.append(gc_count())
 
     assert n[0] == n[1] == n[2], f"objects leaked: {n[1] - n[0]}, {n[2] - n[1]}"
index 47c7966295105898bb17f3c20067f67afb47b82d..871f65d0e1435f079e2c1e59b9145ba62184e930 100644 (file)
@@ -1,5 +1,6 @@
 import gc
 import re
+import sys
 import operator
 from typing import Callable, Optional, Tuple
 
@@ -142,5 +143,37 @@ def gc_collect():
         gc.collect()
 
 
+NO_COUNT_TYPES: Tuple[type, ...] = ()
+
+if sys.version_info[:2] == (3, 10):
+    # On my laptop there are occasional creations of a single one of these objects
+    # with empty content, which might be some Decimal caching.
+    # Keeping the guard as strict as possible, to be extended if other types
+    # or versions are necessary.
+    try:
+        from _contextvars import Context  # type: ignore
+    except ImportError:
+        pass
+    else:
+        NO_COUNT_TYPES += (Context,)
+
+
+def gc_count() -> int:
+    """
+    len(gc.get_objects()), with subtleties.
+    """
+    if not NO_COUNT_TYPES:
+        return len(gc.get_objects())
+
+    # Note: not using a list comprehension because it pollutes the objects list.
+    rv = 0
+    for obj in gc.get_objects():
+        if isinstance(obj, NO_COUNT_TYPES):
+            continue
+        rv += 1
+
+    return rv
+
+
 async def alist(it):
     return [i async for i in it]