diff --git a/ibis/backends/duckdb/tests/test_client.py b/ibis/backends/duckdb/tests/test_client.py index c8b4a4e911836..94a0c028a302f 100644 --- a/ibis/backends/duckdb/tests/test_client.py +++ b/ibis/backends/duckdb/tests/test_client.py @@ -1,5 +1,6 @@ from __future__ import annotations +import gc import os import subprocess import sys @@ -403,3 +404,23 @@ def test_read_csv_with_types(tmp_path, input, all_varchar): path.write_bytes(data) t = con.read_csv(path, all_varchar=all_varchar, **input) assert t.schema()["geom"].is_geospatial() + + +def test_tables_accessor_no_reference_cycle(): + """Test that a single reference to a connection has the desired lifetime semantics.""" + con = ibis.duckdb.connect() + + before = len(gc.get_referrers(con)) + tables = con.tables + after = len(gc.get_referrers(con)) + + assert after == before + + # valid call, and there are no tables in the database + assert not list(tables) + + del con + + # no longer valid because the backend has been manually decref'd + with pytest.raises(ReferenceError): + list(tables) diff --git a/ibis/backends/tests/test_api.py b/ibis/backends/tests/test_api.py index 4b71bdb4ffee8..074c288933da8 100644 --- a/ibis/backends/tests/test_api.py +++ b/ibis/backends/tests/test_api.py @@ -1,5 +1,7 @@ from __future__ import annotations +import gc + import pytest from pytest import param @@ -115,6 +117,16 @@ def test_tables_accessor_repr(con): assert f"- {name}" in result +def test_tables_accessor_no_reference_cycle(con): + before = len(gc.get_referrers(con)) + _ = con.tables + after = len(gc.get_referrers(con)) + + # assert that creating a `tables` accessor object doesn't increase the + # number of strong references + assert after == before + + @pytest.mark.parametrize( "expr_fn", [