From f89062a5f0d673728ed7b6d6a5008cf708d59741 Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 19:40:41 +0000 Subject: [PATCH 01/54] test: Add pytest plugins for - timestamper (timestamps in debug), run-parallel (multi-threading), randomly (random order), and xdist (multiprocessing) --- pyproject.toml | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bcbb24f6..29b1f758 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -227,6 +227,10 @@ test = [ # dependencies used for running tests "pytest", "pytest-reraise", "pytest-timeout", + "pytest-xdist", # multi-processed tests, if `-n | auto` + "pytest-randomly", # randomizes test order to ensure no test dependencies, enabled on install + "pytest-run-parallel", # multi-threaded tests, if `--parallel-threads=N --iterations=N` + "pytest-timestamper", # Adds timestamps to test output "mypy", "coverage", "gcovr; python_version < '3.14'", @@ -306,6 +310,7 @@ filterwarnings = [ "ignore:distutils Version classes are deprecated:DeprecationWarning", "ignore:is_datetime64tz_dtype is deprecated:DeprecationWarning", ] +timeout = 300 # don't let individual tests run for more than 5 minutes [tool.coverage.run] branch = true @@ -382,10 +387,36 @@ manylinux-pypy_aarch64-image = "manylinux_2_28" enable = ["cpython-freethreading", "cpython-prerelease"] [tool.cibuildwheel.linux] -before-build = ["yum install -y ccache"] +environment-pass = ["SCCACHE_GHA_ENABLED", "ACTIONS_RUNTIME_TOKEN", "ACTIONS_RESULTS_URL", "ACTIONS_CACHE_SERVICE_V2", "SCCACHE_C_CUSTOM_CACHE_BUSTER", "PYTHON_GIL"] +before-build = [ + "if [ \"$(uname -m)\" = \"aarch64\" ]; then ARCH=aarch64; else ARCH=x86_64; fi", + "curl -L https://github.com/mozilla/sccache/releases/download/v0.10.0/sccache-v0.10.0-${ARCH}-unknown-linux-musl.tar.gz | tar xz", + "cp sccache-v0.10.0-${ARCH}-unknown-linux-musl/sccache /usr/bin", + "sccache --show-stats"] +before-test = ["sccache --show-stats"] [tool.cibuildwheel.macos] -before-build = ["brew install ccache"] +environment-pass = ["SCCACHE_GHA_ENABLED", "ACTIONS_RUNTIME_TOKEN", "ACTIONS_RESULTS_URL", "ACTIONS_CACHE_SERVICE_V2", "SCCACHE_C_CUSTOM_CACHE_BUSTER", "PYTHON_GIL"] +before-build = ["brew install sccache"] [tool.cibuildwheel.windows] -before-build = ["choco install ccache"] +environment-pass = ["SCCACHE_GHA_ENABLED", "ACTIONS_RUNTIME_TOKEN", "ACTIONS_RESULTS_URL", "ACTIONS_CACHE_SERVICE_V2", "SCCACHE_C_CUSTOM_CACHE_BUSTER", "PYTHON_GIL"] +before-build = [ + "del \"C:\\Strawberry\\c\\bin\\ccache.exe\"", + "choco install sccache"] + +[[tool.scikit-build.overrides]] +# Windows Free-Threading +if.platform-system = "^win32" +if.abi-flags = "t" +inherit.cmake.define = "append" +cmake.define.CMAKE_BUILD_TYPE="" +cmake.define.CMAKE_MSVC_DEBUG_INFORMATION_FORMAT="Embedded" +cmake.define.CMAKE_C_FLAGS="/Z7 /DPy_MOD_GIL_USED /DPy_GIL_DISABLED" +cmake.define.CMAKE_CXX_FLAGS="/Z7 /DPy_MOD_GIL_USED /DPy_GIL_DISABLED" +cmake.args = [ + "-G", "Ninja", + "--log-level=DEBUG", +] +cmake.define.CMAKE_C_COMPILER_LAUNCHER="" +cmake.define.CMAKE_CXX_COMPILER_LAUNCHER="" \ No newline at end of file From c235630e98cbb27373da2e081b9d9018aff06256 Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 19:41:55 +0000 Subject: [PATCH 02/54] test: When using duckdb_cursor fixture, use a distinct database for each test to allow concurrent tests. --- tests/conftest.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 5e297aee..19586787 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -267,11 +267,9 @@ def spark(): @pytest.fixture(scope='function') -def duckdb_cursor(): - connection = duckdb.connect('') - yield connection - connection.close() - +def duckdb_cursor(tmp_path): + with duckdb.connect(tmp_path / "mytest") as connection: + yield connection @pytest.fixture(scope='function') def integers(duckdb_cursor): From f91ea33de940238fd41749ab8979aea70fc8b3c8 Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 19:43:03 +0000 Subject: [PATCH 03/54] test: use tmp_path fixture to allow concurrent tests to run and avoid ordering issues --- tests/fast/api/test_to_csv.py | 96 +++++++++++++++------------ tests/fast/test_many_con_same_file.py | 29 +++----- tests/slow/test_h2oai_arrow.py | 16 ++--- 3 files changed, 70 insertions(+), 71 deletions(-) diff --git a/tests/fast/api/test_to_csv.py b/tests/fast/api/test_to_csv.py index e48ae1b8..768906ef 100644 --- a/tests/fast/api/test_to_csv.py +++ b/tests/fast/api/test_to_csv.py @@ -1,5 +1,4 @@ import duckdb -import tempfile import os import pandas._testing as tm import datetime @@ -10,8 +9,8 @@ class TestToCSV(object): @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_basic_to_csv(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_basic_to_csv(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': [5, 3, 23, 2], 'b': [45, 234, 234, 2]}) rel = duckdb.from_df(df) @@ -21,8 +20,8 @@ def test_basic_to_csv(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_sep(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_sep(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': [5, 3, 23, 2], 'b': [45, 234, 234, 2]}) rel = duckdb.from_df(df) @@ -32,8 +31,8 @@ def test_to_csv_sep(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_na_rep(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_na_rep(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': [5, None, 23, 2], 'b': [45, 234, 234, 2]}) rel = duckdb.from_df(df) @@ -43,8 +42,8 @@ def test_to_csv_na_rep(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_header(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_header(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': [5, None, 23, 2], 'b': [45, 234, 234, 2]}) rel = duckdb.from_df(df) @@ -54,8 +53,8 @@ def test_to_csv_header(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_quotechar(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_quotechar(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ["\'a,b,c\'", None, "hello", "bye"], 'b': [45, 234, 234, 2]}) rel = duckdb.from_df(df) @@ -65,8 +64,8 @@ def test_to_csv_quotechar(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_escapechar(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_escapechar(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame( { "c_bool": [True, False], @@ -81,8 +80,8 @@ def test_to_csv_escapechar(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_date_format(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_date_format(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame(getTimeSeriesData()) dt_index = df.index df = pandas.DataFrame({"A": dt_index, "B": dt_index.shift(1)}, index=dt_index) @@ -94,8 +93,8 @@ def test_to_csv_date_format(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_timestamp_format(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_timestamp_format(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") data = [datetime.time(hour=23, minute=1, second=34, microsecond=234345)] df = pandas.DataFrame({'0': pandas.Series(data=data, dtype='object')}) rel = duckdb.from_df(df) @@ -106,8 +105,8 @@ def test_to_csv_timestamp_format(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_quoting_off(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_quoting_off(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) rel = duckdb.from_df(df) rel.to_csv(temp_file_name, quoting=None) @@ -116,8 +115,8 @@ def test_to_csv_quoting_off(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_quoting_on(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_quoting_on(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) rel = duckdb.from_df(df) rel.to_csv(temp_file_name, quoting="force") @@ -126,8 +125,9 @@ def test_to_csv_quoting_on(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_quoting_quote_all(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_quoting_quote_all(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) rel = duckdb.from_df(df) rel.to_csv(temp_file_name, quoting=csv.QUOTE_ALL) @@ -136,8 +136,9 @@ def test_to_csv_quoting_quote_all(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_encoding_incorrect(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_encoding_incorrect(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) rel = duckdb.from_df(df) with pytest.raises( @@ -146,8 +147,9 @@ def test_to_csv_encoding_incorrect(self, pandas): rel.to_csv(temp_file_name, encoding="nope") @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_encoding_correct(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_encoding_correct(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) rel = duckdb.from_df(df) rel.to_csv(temp_file_name, encoding="UTF-8") @@ -155,8 +157,9 @@ def test_to_csv_encoding_correct(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_compression_gzip(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_compression_gzip(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) rel = duckdb.from_df(df) rel.to_csv(temp_file_name, compression="gzip") @@ -164,8 +167,9 @@ def test_compression_gzip(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_partition(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_partition(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame( { "c_category": ['a', 'a', 'b', 'b'], @@ -190,8 +194,9 @@ def test_to_csv_partition(self, pandas): assert csv_rel.execute().fetchall() == expected @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_partition_with_columns_written(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_partition_with_columns_written(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame( { "c_category": ['a', 'a', 'b', 'b'], @@ -210,8 +215,9 @@ def test_to_csv_partition_with_columns_written(self, pandas): assert res.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_overwrite(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_overwrite(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame( { "c_category_1": ['a', 'a', 'b', 'b'], @@ -238,8 +244,9 @@ def test_to_csv_overwrite(self, pandas): assert csv_rel.execute().fetchall() == expected @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_overwrite_with_columns_written(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_overwrite_with_columns_written(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame( { "c_category_1": ['a', 'a', 'b', 'b'], @@ -264,8 +271,9 @@ def test_to_csv_overwrite_with_columns_written(self, pandas): assert res.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_overwrite_not_enabled(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_overwrite_not_enabled(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame( { "c_category_1": ['a', 'a', 'b', 'b'], @@ -282,8 +290,9 @@ def test_to_csv_overwrite_not_enabled(self, pandas): rel.to_csv(temp_file_name, header=True, partition_by=["c_category_1"]) @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_per_thread_output(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_per_thread_output(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + num_threads = duckdb.sql("select current_setting('threads')").fetchone()[0] print('num_threads:', num_threads) df = pandas.DataFrame( @@ -301,8 +310,9 @@ def test_to_csv_per_thread_output(self, pandas): assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_use_tmp_file(self, pandas): - temp_file_name = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names())) + def test_to_csv_use_tmp_file(self, pandas, tmp_path): + temp_file_name = str(tmp_path / "test.csv") + df = pandas.DataFrame( { "c_category_1": ['a', 'a', 'b', 'b'], diff --git a/tests/fast/test_many_con_same_file.py b/tests/fast/test_many_con_same_file.py index 6b7362a6..fd825c76 100644 --- a/tests/fast/test_many_con_same_file.py +++ b/tests/fast/test_many_con_same_file.py @@ -10,29 +10,20 @@ def get_tables(con): return tbls -def test_multiple_writes(): - try: - os.remove("test.db") - except: - pass - con1 = duckdb.connect("test.db") - con2 = duckdb.connect("test.db") +def test_multiple_writes(tmp_path): + con1 = duckdb.connect(tmp_path / "test.db") + con2 = duckdb.connect(tmp_path / "test.db") con1.execute("CREATE TABLE foo1 as SELECT 1 as a, 2 as b") con2.execute("CREATE TABLE bar1 as SELECT 2 as a, 3 as b") con2.close() con1.close() - con3 = duckdb.connect("test.db") + con3 = duckdb.connect(tmp_path / "test.db") tbls = get_tables(con3) assert tbls == ['bar1', 'foo1'] del con1 del con2 del con3 - try: - os.remove("test.db") - except: - pass - def test_multiple_writes_memory(): con1 = duckdb.connect() @@ -64,23 +55,23 @@ def test_multiple_writes_named_memory(): del con3 -def test_diff_config(): - con1 = duckdb.connect("test.db", False) +def test_diff_config(tmp_path): + con1 = duckdb.connect(tmp_path / "test.db", False) with pytest.raises( duckdb.ConnectionException, match="Can't open a connection to same database file with a different configuration than existing connections", ): - con2 = duckdb.connect("test.db", True) + con2 = duckdb.connect(tmp_path / "test.db", True) con1.close() del con1 -def test_diff_config_extended(): - con1 = duckdb.connect("test.db", config={'null_order': 'NULLS FIRST'}) +def test_diff_config_extended(tmp_path): + con1 = duckdb.connect(tmp_path / "test.db", config={'null_order': 'NULLS FIRST'}) with pytest.raises( duckdb.ConnectionException, match="Can't open a connection to same database file with a different configuration than existing connections", ): - con2 = duckdb.connect("test.db") + con2 = duckdb.connect(tmp_path / "test.db") con1.close() del con1 diff --git a/tests/slow/test_h2oai_arrow.py b/tests/slow/test_h2oai_arrow.py index 40bde07b..7ff37d01 100644 --- a/tests/slow/test_h2oai_arrow.py +++ b/tests/slow/test_h2oai_arrow.py @@ -194,8 +194,10 @@ def test_join(self, threads, function, large_data): @fixture(scope="module") -def arrow_dataset_register(): +def arrow_dataset_register(tmp_path_factory): """Single fixture to download files and register them on the given connection""" + temp_dir = tmp_path_factory.mktemp("h2oai_data") + session = requests.Session() retries = urllib3_util.Retry( allowed_methods={'GET'}, # only retry on GETs (all we do) @@ -212,19 +214,15 @@ def arrow_dataset_register(): respect_retry_after_header=True, # respect Retry-After headers ) session.mount('https://', requests_adapters.HTTPAdapter(max_retries=retries)) - saved_filenames = set() def _register(url, filename, con, tablename): + file_path = temp_dir / filename r = session.get(url) - with open(filename, 'wb') as f: - f.write(r.content) - con.register(tablename, read_csv(filename)) - saved_filenames.add(filename) + file_path.write_bytes(r.content) + con.register(tablename, read_csv(str(file_path))) yield _register - for filename in saved_filenames: - os.remove(filename) session.close() @@ -269,4 +267,4 @@ def group_by_data(arrow_dataset_register): "x", ) yield con - con.close() + con.close() \ No newline at end of file From e0f81b9fa2713f951f4568368cc9e00745e8b0de Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 19:43:39 +0000 Subject: [PATCH 04/54] test: move the 10M row test to tests/slow, as it takes > 1min / is not fast. --- tests/fast/test_relation.py | 8 -------- tests/slow/test_relation_slow.py | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 tests/slow/test_relation_slow.py diff --git a/tests/fast/test_relation.py b/tests/fast/test_relation.py index 8e68c149..2d9b3b4b 100644 --- a/tests/fast/test_relation.py +++ b/tests/fast/test_relation.py @@ -1,6 +1,5 @@ import duckdb import numpy as np -import platform import tempfile import os import pandas as pd @@ -527,13 +526,6 @@ def test_relation_print(self): 2048, 5000, 1000000, - pytest.param( - 10000000, - marks=pytest.mark.skipif( - condition=platform.system() == "Emscripten", - reason="Emscripten/Pyodide builds run out of memory at this scale, and error might not thrown reliably", - ), - ), ], ) def test_materialized_relation(self, duckdb_cursor, num_rows): diff --git a/tests/slow/test_relation_slow.py b/tests/slow/test_relation_slow.py new file mode 100644 index 00000000..cd892985 --- /dev/null +++ b/tests/slow/test_relation_slow.py @@ -0,0 +1,20 @@ +import platform +import pytest + + +class TestRelationSlow(object): + @pytest.mark.skipif( + condition=platform.system() == "Emscripten", + reason="Emscripten/Pyodide builds run out of memory at this scale, and error might not thrown reliably", + ) + def test_materialized_relation_large(self, duckdb_cursor): + """Test materialized relation with 10M rows - moved from fast tests due to 1+ minute runtime""" + # Import the implementation function from the fast test + import sys + import os + sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'fast')) + from test_relation import TestRelation + + # Create instance and call the test with large parameter + test_instance = TestRelation() + test_instance.test_materialized_relation(duckdb_cursor, 10000000) \ No newline at end of file From 2f24ce06ef8708dea541897e1cc05ed2aefe4b8d Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 19:44:07 +0000 Subject: [PATCH 05/54] test: use distinct table names in each test. While doesn't allow thread safety, addresses test order (found via randomly) --- tests/fast/api/test_duckdb_connection.py | 74 ++++++++++++------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/tests/fast/api/test_duckdb_connection.py b/tests/fast/api/test_duckdb_connection.py index 4cb565c1..428fae31 100644 --- a/tests/fast/api/test_duckdb_connection.py +++ b/tests/fast/api/test_duckdb_connection.py @@ -57,28 +57,28 @@ def test_arrow(self): def test_begin_commit(self): duckdb.begin() - duckdb.execute("create table tbl as select 1") + duckdb.execute("create table tbl_1 as select 1") duckdb.commit() - res = duckdb.table("tbl") - duckdb.execute("drop table tbl") + res = duckdb.table("tbl_1") + duckdb.execute("drop table tbl_1") def test_begin_rollback(self): duckdb.begin() - duckdb.execute("create table tbl as select 1") + duckdb.execute("create table tbl_1rb as select 1") duckdb.rollback() with pytest.raises(duckdb.CatalogException): # Table does not exist - res = duckdb.table("tbl") + res = duckdb.table("tbl_1rb") def test_cursor(self): - duckdb.execute("create table tbl as select 3") + duckdb.execute("create table tbl_3 as select 3") duckdb_cursor = duckdb.cursor() - res = duckdb_cursor.table("tbl").fetchall() + res = duckdb_cursor.table("tbl_3").fetchall() assert res == [(3,)] - duckdb_cursor.execute("drop table tbl") + duckdb_cursor.execute("drop table tbl_3") with pytest.raises(duckdb.CatalogException): # 'tbl' no longer exists - duckdb.table("tbl") + duckdb.table("tbl_3") def test_cursor_lifetime(self): con = duckdb.connect() @@ -103,12 +103,12 @@ def test_df(self): assert res == ref def test_duplicate(self): - duckdb.execute("create table tbl as select 5") + duckdb.execute("create table tbl_5 as select 5") dup_conn = duckdb.duplicate() - dup_conn.table("tbl").fetchall() - duckdb.execute("drop table tbl") + dup_conn.table("tbl_5").fetchall() + duckdb.execute("drop table tbl_5") with pytest.raises(duckdb.CatalogException): - dup_conn.table("tbl").fetchall() + dup_conn.table("tbl_5").fetchall() def test_readonly_properties(self): duckdb.execute("select 42") @@ -123,11 +123,11 @@ def test_execute(self): def test_executemany(self): # executemany does not keep an open result set # TODO: shouldn't we also have a version that executes a query multiple times with different parameters, returning all of the results? - duckdb.execute("create table tbl (i integer, j varchar)") - duckdb.executemany("insert into tbl VALUES (?, ?)", [(5, 'test'), (2, 'duck'), (42, 'quack')]) - res = duckdb.table("tbl").fetchall() + duckdb.execute("create table tbl_many (i integer, j varchar)") + duckdb.executemany("insert into tbl_many VALUES (?, ?)", [(5, 'test'), (2, 'duck'), (42, 'quack')]) + res = duckdb.table("tbl_many").fetchall() assert res == [(5, 'test'), (2, 'duck'), (42, 'quack')] - duckdb.execute("drop table tbl") + duckdb.execute("drop table tbl_many") def test_pystatement(self): with pytest.raises(duckdb.ParserException, match='seledct'): @@ -163,8 +163,8 @@ def test_pystatement(self): duckdb.execute(statements[0]) assert duckdb.execute(statements[0], {'1': 42}).fetchall() == [(42,)] - duckdb.execute("create table tbl(a integer)") - statements = duckdb.extract_statements('insert into tbl select $1') + duckdb.execute("create table tbl_a(a integer)") + statements = duckdb.extract_statements('insert into tbl_a select $1') assert statements[0].expected_result_type == [ duckdb.ExpectedResultType.CHANGED_ROWS, duckdb.ExpectedResultType.QUERY_RESULT, @@ -174,23 +174,23 @@ def test_pystatement(self): ): duckdb.executemany(statements[0]) duckdb.executemany(statements[0], [(21,), (22,), (23,)]) - assert duckdb.table('tbl').fetchall() == [(21,), (22,), (23,)] - duckdb.execute("drop table tbl") + assert duckdb.table('tbl_a').fetchall() == [(21,), (22,), (23,)] + duckdb.execute("drop table tbl_a") def test_fetch_arrow_table(self): # Needed for 'fetch_arrow_table' pyarrow = pytest.importorskip("pyarrow") - duckdb.execute("Create Table test (a integer)") + duckdb.execute("Create Table test_arrow_tble (a integer)") for i in range(1024): for j in range(2): - duckdb.execute("Insert Into test values ('" + str(i) + "')") - duckdb.execute("Insert Into test values ('5000')") - duckdb.execute("Insert Into test values ('6000')") + duckdb.execute("Insert Into test_arrow_tble values ('" + str(i) + "')") + duckdb.execute("Insert Into test_arrow_tble values ('5000')") + duckdb.execute("Insert Into test_arrow_tble values ('6000')") sql = ''' SELECT a, COUNT(*) AS repetitions - FROM test + FROM test_arrow_tble GROUP BY a ''' @@ -200,7 +200,7 @@ def test_fetch_arrow_table(self): arrow_df = arrow_table.to_pandas() assert result_df['repetitions'].sum() == arrow_df['repetitions'].sum() - duckdb.execute("drop table test") + duckdb.execute("drop table test_arrow_tble") def test_fetch_df(self): ref = [([1, 2, 3],)] @@ -210,22 +210,22 @@ def test_fetch_df(self): assert res == ref def test_fetch_df_chunk(self): - duckdb.execute("CREATE table t as select range a from range(3000);") - query = duckdb.execute("SELECT a FROM t") + duckdb.execute("CREATE table t_df_chunk as select range a from range(3000);") + query = duckdb.execute("SELECT a FROM t_df_chunk") cur_chunk = query.fetch_df_chunk() assert cur_chunk['a'][0] == 0 assert len(cur_chunk) == 2048 cur_chunk = query.fetch_df_chunk() assert cur_chunk['a'][0] == 2048 assert len(cur_chunk) == 952 - duckdb.execute("DROP TABLE t") + duckdb.execute("DROP TABLE t_df_chunk") def test_fetch_record_batch(self): # Needed for 'fetch_arrow_table' pyarrow = pytest.importorskip("pyarrow") - duckdb.execute("CREATE table t as select range a from range(3000);") - duckdb.execute("SELECT a FROM t") + duckdb.execute("CREATE table t_record_batch as select range a from range(3000);") + duckdb.execute("SELECT a FROM t_record_batch") record_batch_reader = duckdb.fetch_record_batch(1024) chunk = record_batch_reader.read_all() assert len(chunk) == 3000 @@ -289,10 +289,10 @@ def test_register(self): def test_register_relation(self): con = duckdb.connect() rel = con.sql('select [5,4,3]') - con.register("relation", rel) + con.register("relation_rr", rel) - con.sql("create table tbl as select * from relation") - assert con.table('tbl').fetchall() == [([5, 4, 3],)] + con.sql("create table tbl_reg_rel as select * from relation_rr") + assert con.table('tbl_reg_rel').fetchall() == [([5, 4, 3],)] def test_unregister_problematic_behavior(self, duckdb_cursor): # We have a VIEW called 'vw' in the Catalog @@ -333,8 +333,8 @@ def temporary_scope(): def test_table(self): con = duckdb.connect() - con.execute("create table tbl as select 1") - assert [(1,)] == con.table("tbl").fetchall() + con.execute("create table tbl_test_table as select 1") + assert [(1,)] == con.table("tbl_test_table").fetchall() def test_table_function(self): assert None != duckdb.table_function From 2e9d0805988571699bdd038676ae837ac5789f11 Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 19:45:38 +0000 Subject: [PATCH 06/54] test: use pytest-raises to catch the expected error and add a timeout to avoid long tests. This was another cause of fast tests taking too long, sometimes. --- tests/fast/api/test_query_interrupt.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/fast/api/test_query_interrupt.py b/tests/fast/api/test_query_interrupt.py index 6334e475..693945d1 100644 --- a/tests/fast/api/test_query_interrupt.py +++ b/tests/fast/api/test_query_interrupt.py @@ -1,35 +1,31 @@ import duckdb import time import pytest - import platform import threading import _thread as thread def send_keyboard_interrupt(): - # Wait a little, so we're sure the 'execute' has started time.sleep(0.1) - # Send an interrupt to the main thread thread.interrupt_main() class TestQueryInterruption(object): + @pytest.mark.xfail( condition=platform.system() == "Emscripten", reason="Emscripten builds cannot use threads", ) - def test_query_interruption(self): + @pytest.mark.timeout(5) + def test_keyboard_interruption(self): con = duckdb.connect() thread = threading.Thread(target=send_keyboard_interrupt) # Start the thread thread.start() try: - res = con.execute('select count(*) from range(100000000000)').fetchall() - except RuntimeError: - # If this is not reached, we could not cancel the query before it completed - # indicating that the query interruption functionality is broken - assert True - except KeyboardInterrupt: - pytest.fail() - thread.join() + with pytest.raises((KeyboardInterrupt, RuntimeError)): + res = con.execute('select * from range(100000) t1,range(100000) t2').fetchall() + finally: + # Ensure the thread completes regardless of what happens + thread.join() From 8312c34cd020423b6649565e8f4beb3db64042cd Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 19:53:25 +0000 Subject: [PATCH 07/54] ci: reduce the verbosity of the build step by add --quiet to uv export --- .github/workflows/packaging_wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/packaging_wheels.yml b/.github/workflows/packaging_wheels.yml index ea13b674..6616453e 100644 --- a/.github/workflows/packaging_wheels.yml +++ b/.github/workflows/packaging_wheels.yml @@ -54,7 +54,7 @@ jobs: CIBW_TEST_SKIP: ${{ inputs.testsuite == 'none' && '*' || '*-macosx_universal2' }} CIBW_TEST_SOURCES: tests CIBW_BEFORE_TEST: > - uv export --only-group test --no-emit-project --output-file pylock.toml --directory {project} && + uv export --only-group test --no-emit-project --output-file pylock.toml --directory {project} --quiet && uv pip install -r pylock.toml CIBW_TEST_COMMAND: > uv run -v pytest ${{ inputs.testsuite == 'fast' && './tests/fast' || './tests' }} --verbose --ignore=./tests/stubs From 69a10139dfb4c5b13f8292156127d6933b3c3505 Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 20:10:41 +0000 Subject: [PATCH 08/54] revert: restore ccache installs --- pyproject.toml | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 29b1f758..88a74b48 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -387,36 +387,10 @@ manylinux-pypy_aarch64-image = "manylinux_2_28" enable = ["cpython-freethreading", "cpython-prerelease"] [tool.cibuildwheel.linux] -environment-pass = ["SCCACHE_GHA_ENABLED", "ACTIONS_RUNTIME_TOKEN", "ACTIONS_RESULTS_URL", "ACTIONS_CACHE_SERVICE_V2", "SCCACHE_C_CUSTOM_CACHE_BUSTER", "PYTHON_GIL"] -before-build = [ - "if [ \"$(uname -m)\" = \"aarch64\" ]; then ARCH=aarch64; else ARCH=x86_64; fi", - "curl -L https://github.com/mozilla/sccache/releases/download/v0.10.0/sccache-v0.10.0-${ARCH}-unknown-linux-musl.tar.gz | tar xz", - "cp sccache-v0.10.0-${ARCH}-unknown-linux-musl/sccache /usr/bin", - "sccache --show-stats"] -before-test = ["sccache --show-stats"] +before-build = ["yum install -y ccache"] [tool.cibuildwheel.macos] -environment-pass = ["SCCACHE_GHA_ENABLED", "ACTIONS_RUNTIME_TOKEN", "ACTIONS_RESULTS_URL", "ACTIONS_CACHE_SERVICE_V2", "SCCACHE_C_CUSTOM_CACHE_BUSTER", "PYTHON_GIL"] -before-build = ["brew install sccache"] +before-build = ["brew install ccache"] [tool.cibuildwheel.windows] -environment-pass = ["SCCACHE_GHA_ENABLED", "ACTIONS_RUNTIME_TOKEN", "ACTIONS_RESULTS_URL", "ACTIONS_CACHE_SERVICE_V2", "SCCACHE_C_CUSTOM_CACHE_BUSTER", "PYTHON_GIL"] -before-build = [ - "del \"C:\\Strawberry\\c\\bin\\ccache.exe\"", - "choco install sccache"] - -[[tool.scikit-build.overrides]] -# Windows Free-Threading -if.platform-system = "^win32" -if.abi-flags = "t" -inherit.cmake.define = "append" -cmake.define.CMAKE_BUILD_TYPE="" -cmake.define.CMAKE_MSVC_DEBUG_INFORMATION_FORMAT="Embedded" -cmake.define.CMAKE_C_FLAGS="/Z7 /DPy_MOD_GIL_USED /DPy_GIL_DISABLED" -cmake.define.CMAKE_CXX_FLAGS="/Z7 /DPy_MOD_GIL_USED /DPy_GIL_DISABLED" -cmake.args = [ - "-G", "Ninja", - "--log-level=DEBUG", -] -cmake.define.CMAKE_C_COMPILER_LAUNCHER="" -cmake.define.CMAKE_CXX_COMPILER_LAUNCHER="" \ No newline at end of file +before-build = ["choco install ccache"] From 57c543c574236cb0e63d1102e09a976f20f0baa8 Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 22:27:17 +0000 Subject: [PATCH 09/54] CI: Add a Stress Tests workflow --- .github/workflows/additional_testing.yml | 172 +++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 .github/workflows/additional_testing.yml diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml new file mode 100644 index 00000000..a4e17f29 --- /dev/null +++ b/.github/workflows/additional_testing.yml @@ -0,0 +1,172 @@ +name: Stress Tests +on: + push: + workflow_dispatch: + inputs: + os: + description: Operating System + required: true + type: choice + default: ubuntu-24.04 + options: + - windows-2025 + - ubuntu-24.04 + - ubuntu-24.04-arm + - macos-15 + - macos-13 + python_version: + description: Python Version + required: true + type: choice + default: cp314 + options: + - cp39 + - cp310 + - cp311 + - cp312 + - cp313 + - cp314 + - cp314t + testsuite: + type: choice + description: Testsuite to run (fast, all) + required: true + default: fast + options: + - fast + - all + duckdb-python-sha: + type: string + description: The commit or ref to build against (defaults to latest commit of current ref) + required: false + duckdb-sha: + type: string + description: Override the DuckDB submodule commit or ref to build against + required: false + test_iterations: + type: number + description: Number of times to run each test phase + required: false + default: 3 + +env: + OS_TO_USE: ${{ inputs.os || 'ubuntu-24.04' }} + PYTHON_VERSION_TO_USE: ${{ inputs.python_version || 'cp314' }} + TESTSUITE_TO_USE: ${{ inputs.testsuite || 'fast' }} + ITERATIONS_TO_USE: ${{ inputs.test_iterations || '3' }} + # Platform-specific ccache installation commands + CIBW_BEFORE_BUILD_LINUX: "yum install -y ccache" + CIBW_BEFORE_BUILD_MACOS: "brew install ccache" + CIBW_BEFORE_BUILD_WINDOWS: "choco install ccache" + + +jobs: + build: + name: "Build wheel: ${{ inputs.python_version || 'cp314' }}-${{ inputs.os || 'ubuntu-24.04' }}" + runs-on: ${{ inputs.os || 'ubuntu-24.04' }} + + steps: + - name: Checkout DuckDB Python + uses: actions/checkout@v4 + with: + ref: ${{ inputs.duckdb-python-sha }} + fetch-depth: 0 + submodules: true + + - name: Checkout DuckDB + shell: bash + if: ${{ inputs.duckdb-sha }} + run: | + cd external/duckdb + git fetch origin + git checkout ${{ inputs.duckdb-sha }} + + - uses: astral-sh/setup-uv@v6 + with: + version: "0.8.16" + enable-cache: false + cache-suffix: -${{ env.PYTHON_VERSION_TO_USE }}-${{ env.OS_TO_USE }} + python-version: ${{ env.PYTHON_VERSION_TO_USE }} + + - name: Build wheel + uses: pypa/cibuildwheel@v3.1 + env: + CIBW_ARCHS: auto + CIBW_BUILD: ${{ env.PYTHON_VERSION_TO_USE }}-* + CIBW_TEST_SKIP: '*' + CIBW_BEFORE_BUILD_LINUX: ${{ env.CIBW_BEFORE_BUILD_LINUX }} + CIBW_BEFORE_BUILD_MACOS: ${{ env.CIBW_BEFORE_BUILD_MACOS }} + CIBW_BEFORE_BUILD_WINDOWS: ${{ env.CIBW_BEFORE_BUILD_WINDOWS }} + + - name: Upload wheel + uses: actions/upload-artifact@v4 + with: + name: wheel-${{ env.PYTHON_VERSION_TO_USE }}-${{ env.OS_TO_USE }} + path: wheelhouse/ + + test: + name: 'Test: ${{ matrix.pytest_config.name }} - ${{ inputs.python_version }}-${{ inputs.os }}' + runs-on: ${{ inputs.os }} + needs: build + strategy: + fail-fast: false + matrix: + pytest_config: + - name: "Random Order" # randomization is automatic due to pytest-randomly + args: "" + iterations: ${{ inputs.test_iterations || 3 }} + - name: "Multiprocess" # uses pytest-xdist + args: "-n auto" + iterations: ${{ inputs.test_iterations || 3 }} + - name: "Threaded" # uses pytest-run-parallel + # TODO: Update to use threading specific tests or explicitly mark unsafe tests. test_module was chosen as an example. + args: "--parallel-threads=4 --iterations=8 tests/fast/test_module.py --ignore" + iterations: 1 + + steps: + - name: Checkout DuckDB Python + uses: actions/checkout@v4 + with: + ref: ${{ inputs.duckdb-python-sha }} + fetch-depth: 0 + submodules: true + + - uses: astral-sh/setup-uv@v6 + with: + version: "0.8.16" + enable-cache: false + cache-suffix: -${{ env.PYTHON_VERSION_TO_USE }}-${{ env.OS_TO_USE }} + python-version: ${{ env.PYTHON_VERSION_TO_USE }} + + - name: Download wheel + uses: actions/download-artifact@v4 + with: + name: wheel-${{ env.PYTHON_VERSION_TO_USE }}-${{ env.OS_TO_USE }} + path: wheelhouse/ + + - name: Install dependencies + shell: bash + run: | + uv export --only-group test --no-emit-project --output-file pylock.toml + uv pip install -r pylock.toml + uv pip install wheelhouse/*.whl + + - name: Run ${{ matrix.pytest_config.name }} tests + shell: bash + run: | + TEST_TARGET="${{ inputs.testsuite == 'fast' && 'tests/fast' || 'tests' }}" + ITERATIONS="${{ matrix.pytest_config.iterations }}" + PYTEST_ARGS="${{ matrix.pytest_config.args }}" + + echo "Running ${{ matrix.pytest_config.name }} pytest $ITERATIONS times against: $TEST_TARGET" + for i in $(seq 1 $ITERATIONS); do + echo "" + echo "${{ matrix.pytest_config.name }} Run $i/$ITERATIONS:" + echo "--------" + uv run pytest $PYTEST_ARGS "$TEST_TARGET" --durations=5 + if [ $? -ne 0 ]; then + echo "${{ matrix.pytest_config.name }} Run $i failed!" + else + echo "${{ matrix.pytest_config.name }} Run $i passed!" + fi + done \ No newline at end of file From bea2a704dd66381c4c05724cd504973b07dcbd10 Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Wed, 17 Sep 2025 23:10:24 +0000 Subject: [PATCH 10/54] test: add a default_con fixture that guarantees a "clean" connection, marked thread_unsafe --- pyproject.toml | 3 + tests/conftest.py | 10 +++ tests/fast/api/test_to_csv.py | 128 +++++++++++++++++----------------- 3 files changed, 77 insertions(+), 64 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 88a74b48..d2a20f53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -311,6 +311,9 @@ filterwarnings = [ "ignore:is_datetime64tz_dtype is deprecated:DeprecationWarning", ] timeout = 300 # don't let individual tests run for more than 5 minutes +thread_unsafe_fixtures = [ # https://pypi.org/project/pytest-run-parallel/ + 'default_con' +] [tool.coverage.run] branch = true diff --git a/tests/conftest.py b/tests/conftest.py index 19586787..b2462e37 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -271,6 +271,16 @@ def duckdb_cursor(tmp_path): with duckdb.connect(tmp_path / "mytest") as connection: yield connection + +@pytest.fixture(scope='function') +def default_con(): + # ensures each test uses a fresh default connection to avoid test leakage + # threading_unsafe fixture, marked as such in pyproject.toml + duckdb.default_connection().close() + with duckdb.default_connection() as conn: + yield conn + + @pytest.fixture(scope='function') def integers(duckdb_cursor): cursor = duckdb_cursor diff --git a/tests/fast/api/test_to_csv.py b/tests/fast/api/test_to_csv.py index 768906ef..8a791c14 100644 --- a/tests/fast/api/test_to_csv.py +++ b/tests/fast/api/test_to_csv.py @@ -9,62 +9,62 @@ class TestToCSV(object): @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_basic_to_csv(self, pandas, tmp_path): + def test_basic_to_csv(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': [5, 3, 23, 2], 'b': [45, 234, 234, 2]}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name) - csv_rel = duckdb.read_csv(temp_file_name) + csv_rel = default_con.read_csv(temp_file_name) assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_sep(self, pandas, tmp_path): + def test_to_csv_sep(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': [5, 3, 23, 2], 'b': [45, 234, 234, 2]}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, sep=',') - csv_rel = duckdb.read_csv(temp_file_name, sep=',') + csv_rel = default_con.read_csv(temp_file_name, sep=',') assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_na_rep(self, pandas, tmp_path): + def test_to_csv_na_rep(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': [5, None, 23, 2], 'b': [45, 234, 234, 2]}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, na_rep="test") - csv_rel = duckdb.read_csv(temp_file_name, na_values="test") + csv_rel = default_con.read_csv(temp_file_name, na_values="test") assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_header(self, pandas, tmp_path): + def test_to_csv_header(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': [5, None, 23, 2], 'b': [45, 234, 234, 2]}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name) - csv_rel = duckdb.read_csv(temp_file_name) + csv_rel = default_con.read_csv(temp_file_name) assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_quotechar(self, pandas, tmp_path): + def test_to_csv_quotechar(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ["\'a,b,c\'", None, "hello", "bye"], 'b': [45, 234, 234, 2]}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, quotechar='\'', sep=',') - csv_rel = duckdb.read_csv(temp_file_name, sep=',', quotechar='\'') + csv_rel = default_con.read_csv(temp_file_name, sep=',', quotechar='\'') assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_escapechar(self, pandas, tmp_path): + def test_to_csv_escapechar(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame( { @@ -74,100 +74,100 @@ def test_to_csv_escapechar(self, pandas, tmp_path): "c_string": ["a", "b,c"], } ) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, quotechar='"', escapechar='!') - csv_rel = duckdb.read_csv(temp_file_name, quotechar='"', escapechar='!') + csv_rel = default_con.read_csv(temp_file_name, quotechar='"', escapechar='!') assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_date_format(self, pandas, tmp_path): + def test_to_csv_date_format(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame(getTimeSeriesData()) dt_index = df.index df = pandas.DataFrame({"A": dt_index, "B": dt_index.shift(1)}, index=dt_index) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, date_format="%Y%m%d") - csv_rel = duckdb.read_csv(temp_file_name, date_format="%Y%m%d") + csv_rel = default_con.read_csv(temp_file_name, date_format="%Y%m%d") assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_timestamp_format(self, pandas, tmp_path): + def test_to_csv_timestamp_format(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") data = [datetime.time(hour=23, minute=1, second=34, microsecond=234345)] df = pandas.DataFrame({'0': pandas.Series(data=data, dtype='object')}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, timestamp_format='%m/%d/%Y') - csv_rel = duckdb.read_csv(temp_file_name, timestamp_format='%m/%d/%Y') + csv_rel = default_con.read_csv(temp_file_name, timestamp_format='%m/%d/%Y') assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_quoting_off(self, pandas, tmp_path): + def test_to_csv_quoting_off(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, quoting=None) - csv_rel = duckdb.read_csv(temp_file_name) + csv_rel = default_con.read_csv(temp_file_name) assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_quoting_on(self, pandas, tmp_path): + def test_to_csv_quoting_on(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, quoting="force") - csv_rel = duckdb.read_csv(temp_file_name) + csv_rel = default_con.read_csv(temp_file_name) assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_quoting_quote_all(self, pandas, tmp_path): + def test_to_csv_quoting_quote_all(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, quoting=csv.QUOTE_ALL) - csv_rel = duckdb.read_csv(temp_file_name) + csv_rel = default_con.read_csv(temp_file_name) assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_encoding_incorrect(self, pandas, tmp_path): + def test_to_csv_encoding_incorrect(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) with pytest.raises( duckdb.InvalidInputException, match="Invalid Input Error: The only supported encoding option is 'UTF8" ): rel.to_csv(temp_file_name, encoding="nope") @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_encoding_correct(self, pandas, tmp_path): + def test_to_csv_encoding_correct(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, encoding="UTF-8") - csv_rel = duckdb.read_csv(temp_file_name) + csv_rel = default_con.read_csv(temp_file_name) assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_compression_gzip(self, pandas, tmp_path): + def test_compression_gzip(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame({'a': ['string1', 'string2', 'string3']}) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, compression="gzip") - csv_rel = duckdb.read_csv(temp_file_name, compression="gzip") + csv_rel = default_con.read_csv(temp_file_name, compression="gzip") assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_partition(self, pandas, tmp_path): + def test_to_csv_partition(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame( @@ -179,9 +179,9 @@ def test_to_csv_partition(self, pandas, tmp_path): "c_string": ["a", "b,c", "e", "f"], } ) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, header=True, partition_by=["c_category"]) - csv_rel = duckdb.sql( + csv_rel = default_con.sql( f'''FROM read_csv_auto('{temp_file_name}/*/*.csv', hive_partitioning=TRUE, header=TRUE);''' ) expected = [ @@ -194,7 +194,7 @@ def test_to_csv_partition(self, pandas, tmp_path): assert csv_rel.execute().fetchall() == expected @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_partition_with_columns_written(self, pandas, tmp_path): + def test_to_csv_partition_with_columns_written(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame( @@ -206,16 +206,16 @@ def test_to_csv_partition_with_columns_written(self, pandas, tmp_path): "c_string": ["a", "b,c", "e", "f"], } ) - rel = duckdb.from_df(df) - res = duckdb.sql("FROM rel order by all") + rel = default_con.from_df(df) + res = default_con.sql("FROM rel order by all") rel.to_csv(temp_file_name, header=True, partition_by=["c_category"], write_partition_columns=True) - csv_rel = duckdb.sql( + csv_rel = default_con.sql( f'''FROM read_csv_auto('{temp_file_name}/*/*.csv', hive_partitioning=TRUE, header=TRUE) order by all;''' ) assert res.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_overwrite(self, pandas, tmp_path): + def test_to_csv_overwrite(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame( @@ -228,10 +228,10 @@ def test_to_csv_overwrite(self, pandas, tmp_path): "c_string": ["a", "b,c", "e", "f"], } ) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, header=True, partition_by=["c_category_1"]) # csv to be overwritten rel.to_csv(temp_file_name, header=True, partition_by=["c_category_1"], overwrite=True) - csv_rel = duckdb.sql( + csv_rel = default_con.sql( f'''FROM read_csv_auto('{temp_file_name}/*/*.csv', hive_partitioning=TRUE, header=TRUE);''' ) # When partition columns are read from directory names, column order become different from original @@ -244,7 +244,7 @@ def test_to_csv_overwrite(self, pandas, tmp_path): assert csv_rel.execute().fetchall() == expected @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_overwrite_with_columns_written(self, pandas, tmp_path): + def test_to_csv_overwrite_with_columns_written(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame( @@ -257,21 +257,21 @@ def test_to_csv_overwrite_with_columns_written(self, pandas, tmp_path): "c_string": ["a", "b,c", "e", "f"], } ) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv( temp_file_name, header=True, partition_by=["c_category_1"], write_partition_columns=True ) # csv to be overwritten rel.to_csv( temp_file_name, header=True, partition_by=["c_category_1"], overwrite=True, write_partition_columns=True ) - csv_rel = duckdb.sql( + csv_rel = default_con.sql( f'''FROM read_csv_auto('{temp_file_name}/*/*.csv', hive_partitioning=TRUE, header=TRUE) order by all;''' ) - res = duckdb.sql("FROM rel order by all") + res = default_con.sql("FROM rel order by all") assert res.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_overwrite_not_enabled(self, pandas, tmp_path): + def test_to_csv_overwrite_not_enabled(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame( @@ -284,16 +284,16 @@ def test_to_csv_overwrite_not_enabled(self, pandas, tmp_path): "c_string": ["a", "b,c", "e", "f"], } ) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, header=True, partition_by=["c_category_1"]) with pytest.raises(duckdb.IOException, match="OVERWRITE"): rel.to_csv(temp_file_name, header=True, partition_by=["c_category_1"]) @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_per_thread_output(self, pandas, tmp_path): + def test_to_csv_per_thread_output(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") - num_threads = duckdb.sql("select current_setting('threads')").fetchone()[0] + num_threads = default_con.sql("select current_setting('threads')").fetchone()[0] print('num_threads:', num_threads) df = pandas.DataFrame( { @@ -304,13 +304,13 @@ def test_to_csv_per_thread_output(self, pandas, tmp_path): "c_string": ["a", "b,c", "e", "f"], } ) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, header=True, per_thread_output=True) - csv_rel = duckdb.read_csv(f'{temp_file_name}/*.csv', header=True) + csv_rel = default_con.read_csv(f'{temp_file_name}/*.csv', header=True) assert rel.execute().fetchall() == csv_rel.execute().fetchall() @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_to_csv_use_tmp_file(self, pandas, tmp_path): + def test_to_csv_use_tmp_file(self, pandas, tmp_path, default_con): temp_file_name = str(tmp_path / "test.csv") df = pandas.DataFrame( @@ -323,8 +323,8 @@ def test_to_csv_use_tmp_file(self, pandas, tmp_path): "c_string": ["a", "b,c", "e", "f"], } ) - rel = duckdb.from_df(df) + rel = default_con.from_df(df) rel.to_csv(temp_file_name, header=True) # csv to be overwritten rel.to_csv(temp_file_name, header=True, use_tmp_file=True) - csv_rel = duckdb.read_csv(temp_file_name, header=True) + csv_rel = default_con.read_csv(temp_file_name, header=True) assert rel.execute().fetchall() == csv_rel.execute().fetchall() From 7a5f672ff9c11cb56b254e0bc20791de925941b5 Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Thu, 18 Sep 2025 00:15:40 +0000 Subject: [PATCH 11/54] tests: fix test use of default connection --- tests/fast/api/test_duckdb_connection.py | 53 ++++++++++++------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/tests/fast/api/test_duckdb_connection.py b/tests/fast/api/test_duckdb_connection.py index 428fae31..6ebd948e 100644 --- a/tests/fast/api/test_duckdb_connection.py +++ b/tests/fast/api/test_duckdb_connection.py @@ -24,23 +24,23 @@ def tmp_database(tmp_path_factory): # wrapped by the 'duckdb' module, to execute with the 'default_connection' class TestDuckDBConnection(object): @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_append(self, pandas): - duckdb.execute("Create table integers (i integer)") + def test_append(self, pandas, default_con): + default_con.execute("Create table integers (i integer)") df_in = pandas.DataFrame( { 'numbers': [1, 2, 3, 4, 5], } ) - duckdb.append('integers', df_in) - assert duckdb.execute('select count(*) from integers').fetchone()[0] == 5 + default_con.append('integers', df_in) + assert default_con.execute('select count(*) from integers').fetchone()[0] == 5 # cleanup - duckdb.execute("drop table integers") + default_con.execute("drop table integers") - def test_default_connection_from_connect(self): - duckdb.sql('create or replace table connect_default_connect (i integer)') + def test_default_connection_from_connect(self, default_con): + default_con.sql('create or replace table connect_default_connect (i integer)') con = duckdb.connect(':default:') con.sql('select i from connect_default_connect') - duckdb.sql('drop table connect_default_connect') + default_con.sql('drop table connect_default_connect') with pytest.raises(duckdb.Error): con.sql('select i from connect_default_connect') @@ -62,26 +62,26 @@ def test_begin_commit(self): res = duckdb.table("tbl_1") duckdb.execute("drop table tbl_1") - def test_begin_rollback(self): - duckdb.begin() - duckdb.execute("create table tbl_1rb as select 1") - duckdb.rollback() + def test_begin_rollback(self, default_con): + default_con.begin() + default_con.execute("create table tbl_1rb as select 1") + default_con.rollback() with pytest.raises(duckdb.CatalogException): # Table does not exist - res = duckdb.table("tbl_1rb") + res = default_con.table("tbl_1rb") - def test_cursor(self): - duckdb.execute("create table tbl_3 as select 3") + def test_cursor(self, default_con): + default_con.execute("create table tbl_3 as select 3") duckdb_cursor = duckdb.cursor() res = duckdb_cursor.table("tbl_3").fetchall() assert res == [(3,)] duckdb_cursor.execute("drop table tbl_3") with pytest.raises(duckdb.CatalogException): # 'tbl' no longer exists - duckdb.table("tbl_3") + default_con.table("tbl_3") - def test_cursor_lifetime(self): - con = duckdb.connect() + def test_cursor_lifetime(self, default_con): + con = default_con def use_cursors(): cursors = [] @@ -286,8 +286,8 @@ def test_query(self): def test_register(self): assert None != duckdb.register - def test_register_relation(self): - con = duckdb.connect() + def test_register_relation(self, default_con): + con = default_con rel = con.sql('select [5,4,3]') con.register("relation_rr", rel) @@ -314,10 +314,10 @@ def test_unregister_problematic_behavior(self, duckdb_cursor): assert duckdb_cursor.execute("select * from vw").fetchone() == (0,) @pytest.mark.parametrize('pandas', [NumpyPandas(), ArrowPandas()]) - def test_relation_out_of_scope(self, pandas): + def test_relation_out_of_scope(self, pandas, default_con): def temporary_scope(): # Create a connection, we will return this - con = duckdb.connect() + con = default_con # Create a dataframe df = pandas.DataFrame({'a': [1, 2, 3]}) # The dataframe has to be registered as well @@ -356,16 +356,15 @@ def test_close(self): def test_interrupt(self): assert None != duckdb.interrupt - def test_wrap_shadowing(self): + def test_wrap_shadowing(self, default_con): pd = NumpyPandas() - import duckdb df = pd.DataFrame({"a": [1, 2, 3]}) - res = duckdb.sql("from df").fetchall() + res = default_con.sql("from df").fetchall() assert res == [(1,), (2,), (3,)] - def test_wrap_coverage(self): - con = duckdb.default_connection + def test_wrap_coverage(self, default_con): + con = default_con # Skip all of the initial __xxxx__ methods connection_methods = dir(con) From 87630455794dc54b7bad6f98da0b5a24ecf65ac4 Mon Sep 17 00:00:00 2001 From: Paul Timmins Date: Thu, 18 Sep 2025 01:06:08 +0000 Subject: [PATCH 12/54] test: be more generous with test_keyboard_interruption timeout: 15s --- tests/fast/api/test_query_interrupt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fast/api/test_query_interrupt.py b/tests/fast/api/test_query_interrupt.py index 693945d1..86274e7f 100644 --- a/tests/fast/api/test_query_interrupt.py +++ b/tests/fast/api/test_query_interrupt.py @@ -17,7 +17,7 @@ class TestQueryInterruption(object): condition=platform.system() == "Emscripten", reason="Emscripten builds cannot use threads", ) - @pytest.mark.timeout(5) + @pytest.mark.timeout(15) def test_keyboard_interruption(self): con = duckdb.connect() thread = threading.Thread(target=send_keyboard_interrupt) From f361b083da33745dadddabb1b7b16a6f588e728c Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Wed, 17 Sep 2025 21:34:00 -0400 Subject: [PATCH 13/54] disable package installs --- .github/workflows/additional_testing.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index a4e17f29..cc652245 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -55,9 +55,9 @@ env: TESTSUITE_TO_USE: ${{ inputs.testsuite || 'fast' }} ITERATIONS_TO_USE: ${{ inputs.test_iterations || '3' }} # Platform-specific ccache installation commands - CIBW_BEFORE_BUILD_LINUX: "yum install -y ccache" - CIBW_BEFORE_BUILD_MACOS: "brew install ccache" - CIBW_BEFORE_BUILD_WINDOWS: "choco install ccache" + CIBW_BEFORE_BUILD_LINUX: "" + CIBW_BEFORE_BUILD_MACOS: "" + CIBW_BEFORE_BUILD_WINDOWS: "" jobs: From 81edd9003887b2ddd2ef58b710d8b985416f9873 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Wed, 17 Sep 2025 21:36:42 -0400 Subject: [PATCH 14/54] ci: update comment --- .github/workflows/additional_testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index cc652245..d976c582 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -54,7 +54,7 @@ env: PYTHON_VERSION_TO_USE: ${{ inputs.python_version || 'cp314' }} TESTSUITE_TO_USE: ${{ inputs.testsuite || 'fast' }} ITERATIONS_TO_USE: ${{ inputs.test_iterations || '3' }} - # Platform-specific ccache installation commands + # Override the ccache installs - unnecessary CIBW_BEFORE_BUILD_LINUX: "" CIBW_BEFORE_BUILD_MACOS: "" CIBW_BEFORE_BUILD_WINDOWS: "" From 86afd8d72856532624d76d7b0155d75790554867 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Wed, 17 Sep 2025 22:56:19 -0400 Subject: [PATCH 15/54] ci: install and no-build --- .github/workflows/additional_testing.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index d976c582..20220cf4 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -147,8 +147,9 @@ jobs: - name: Install dependencies shell: bash run: | - uv export --only-group test --no-emit-project --output-file pylock.toml - uv pip install -r pylock.toml + mkdir workdir + cd workdir + uv sync --no-install-project uv pip install wheelhouse/*.whl - name: Run ${{ matrix.pytest_config.name }} tests @@ -163,7 +164,7 @@ jobs: echo "" echo "${{ matrix.pytest_config.name }} Run $i/$ITERATIONS:" echo "--------" - uv run pytest $PYTEST_ARGS "$TEST_TARGET" --durations=5 + uv run --no-build pytest $PYTEST_ARGS "$TEST_TARGET" --durations=5 if [ $? -ne 0 ]; then echo "${{ matrix.pytest_config.name }} Run $i failed!" else From 8218e548f06ba659677a90c2816256faa869a9ba Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Wed, 17 Sep 2025 23:03:31 -0400 Subject: [PATCH 16/54] ci: move environment variables to appropriate step --- .github/workflows/additional_testing.yml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 20220cf4..3f6f0b9f 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -54,12 +54,7 @@ env: PYTHON_VERSION_TO_USE: ${{ inputs.python_version || 'cp314' }} TESTSUITE_TO_USE: ${{ inputs.testsuite || 'fast' }} ITERATIONS_TO_USE: ${{ inputs.test_iterations || '3' }} - # Override the ccache installs - unnecessary - CIBW_BEFORE_BUILD_LINUX: "" - CIBW_BEFORE_BUILD_MACOS: "" - CIBW_BEFORE_BUILD_WINDOWS: "" - - + jobs: build: name: "Build wheel: ${{ inputs.python_version || 'cp314' }}-${{ inputs.os || 'ubuntu-24.04' }}" @@ -94,10 +89,10 @@ jobs: CIBW_ARCHS: auto CIBW_BUILD: ${{ env.PYTHON_VERSION_TO_USE }}-* CIBW_TEST_SKIP: '*' - CIBW_BEFORE_BUILD_LINUX: ${{ env.CIBW_BEFORE_BUILD_LINUX }} - CIBW_BEFORE_BUILD_MACOS: ${{ env.CIBW_BEFORE_BUILD_MACOS }} - CIBW_BEFORE_BUILD_WINDOWS: ${{ env.CIBW_BEFORE_BUILD_WINDOWS }} - + CIBW_BEFORE_BUILD_LINUX: "" + CIBW_BEFORE_BUILD_MACOS: "" + CIBW_BEFORE_BUILD_WINDOWS: "" + - name: Upload wheel uses: actions/upload-artifact@v4 with: @@ -147,8 +142,6 @@ jobs: - name: Install dependencies shell: bash run: | - mkdir workdir - cd workdir uv sync --no-install-project uv pip install wheelhouse/*.whl From 52360f2506238af4d77589c1913068ee0cfc03be Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 00:53:17 -0400 Subject: [PATCH 17/54] ci: simplify workflow --- .github/workflows/additional_testing.yml | 103 ++++++----------------- 1 file changed, 26 insertions(+), 77 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 3f6f0b9f..8b1e1340 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -1,81 +1,29 @@ name: Stress Tests on: push: - workflow_dispatch: - inputs: - os: - description: Operating System - required: true - type: choice - default: ubuntu-24.04 - options: - - windows-2025 - - ubuntu-24.04 - - ubuntu-24.04-arm - - macos-15 - - macos-13 - python_version: - description: Python Version - required: true - type: choice - default: cp314 - options: - - cp39 - - cp310 - - cp311 - - cp312 - - cp313 - - cp314 - - cp314t - testsuite: - type: choice - description: Testsuite to run (fast, all) - required: true - default: fast - options: - - fast - - all - duckdb-python-sha: - type: string - description: The commit or ref to build against (defaults to latest commit of current ref) - required: false - duckdb-sha: - type: string - description: Override the DuckDB submodule commit or ref to build against - required: false - test_iterations: - type: number - description: Number of times to run each test phase - required: false - default: 3 env: - OS_TO_USE: ${{ inputs.os || 'ubuntu-24.04' }} - PYTHON_VERSION_TO_USE: ${{ inputs.python_version || 'cp314' }} - TESTSUITE_TO_USE: ${{ inputs.testsuite || 'fast' }} - ITERATIONS_TO_USE: ${{ inputs.test_iterations || '3' }} - + OS_TO_USE: ubuntu-24.04 + ARCH_TO_USE: x86_64 + CIBW_SYSTEM_TO_USE: manylinux + PYTHON_VERSION_TO_USE: cp313 + TESTSUITE_TO_USE: fast + ITERATIONS_TO_USE: 3 + + + jobs: build: - name: "Build wheel: ${{ inputs.python_version || 'cp314' }}-${{ inputs.os || 'ubuntu-24.04' }}" - runs-on: ${{ inputs.os || 'ubuntu-24.04' }} + name: "Build wheel: ${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }}" + runs-on: ${{ env.OS_TO_USE }} steps: - name: Checkout DuckDB Python uses: actions/checkout@v4 with: - ref: ${{ inputs.duckdb-python-sha }} fetch-depth: 0 submodules: true - - name: Checkout DuckDB - shell: bash - if: ${{ inputs.duckdb-sha }} - run: | - cd external/duckdb - git fetch origin - git checkout ${{ inputs.duckdb-sha }} - - uses: astral-sh/setup-uv@v6 with: version: "0.8.16" @@ -86,22 +34,23 @@ jobs: - name: Build wheel uses: pypa/cibuildwheel@v3.1 env: - CIBW_ARCHS: auto - CIBW_BUILD: ${{ env.PYTHON_VERSION_TO_USE }}-* + CIBW_ARCHS: ${{ env.ARCH_TO_USE == 'amd64' && 'AMD64' || env.ARCH_TO_USE }} + CIBW_BUILD: ${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }} CIBW_TEST_SKIP: '*' + # Platform-specific ccache installation commands CIBW_BEFORE_BUILD_LINUX: "" CIBW_BEFORE_BUILD_MACOS: "" CIBW_BEFORE_BUILD_WINDOWS: "" - + - name: Upload wheel uses: actions/upload-artifact@v4 with: - name: wheel-${{ env.PYTHON_VERSION_TO_USE }}-${{ env.OS_TO_USE }} + name: wheel-${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }} path: wheelhouse/ test: - name: 'Test: ${{ matrix.pytest_config.name }} - ${{ inputs.python_version }}-${{ inputs.os }}' - runs-on: ${{ inputs.os }} + name: 'Test: ${{ matrix.pytest_config.name }} - ${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }}' + runs-on: ${{ env.OS_TO_USE }} needs: build strategy: fail-fast: false @@ -109,12 +58,12 @@ jobs: pytest_config: - name: "Random Order" # randomization is automatic due to pytest-randomly args: "" - iterations: ${{ inputs.test_iterations || 3 }} + iterations: 3 - name: "Multiprocess" # uses pytest-xdist args: "-n auto" - iterations: ${{ inputs.test_iterations || 3 }} + iterations: 3 - name: "Threaded" # uses pytest-run-parallel - # TODO: Update to use threading specific tests or explicitly mark unsafe tests. test_module was chosen as an example. + # TODO: Update to use threading specific tests or explicitly mark unsafe tests. test_module was chosen as an example. args: "--parallel-threads=4 --iterations=8 tests/fast/test_module.py --ignore" iterations: 1 @@ -122,7 +71,6 @@ jobs: - name: Checkout DuckDB Python uses: actions/checkout@v4 with: - ref: ${{ inputs.duckdb-python-sha }} fetch-depth: 0 submodules: true @@ -136,19 +84,20 @@ jobs: - name: Download wheel uses: actions/download-artifact@v4 with: - name: wheel-${{ env.PYTHON_VERSION_TO_USE }}-${{ env.OS_TO_USE }} + name: wheel-${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }} path: wheelhouse/ - name: Install dependencies shell: bash run: | - uv sync --no-install-project + uv export --only-group test --no-emit-project --output-file pylock.toml + uv pip install -r pylock.toml uv pip install wheelhouse/*.whl - name: Run ${{ matrix.pytest_config.name }} tests shell: bash run: | - TEST_TARGET="${{ inputs.testsuite == 'fast' && 'tests/fast' || 'tests' }}" + TEST_TARGET="tests/fast" ITERATIONS="${{ matrix.pytest_config.iterations }}" PYTEST_ARGS="${{ matrix.pytest_config.args }}" @@ -157,7 +106,7 @@ jobs: echo "" echo "${{ matrix.pytest_config.name }} Run $i/$ITERATIONS:" echo "--------" - uv run --no-build pytest $PYTEST_ARGS "$TEST_TARGET" --durations=5 + uv run pytest $PYTEST_ARGS "$TEST_TARGET" --durations=5 if [ $? -ne 0 ]; then echo "${{ matrix.pytest_config.name }} Run $i failed!" else From a8d97f42dc4b9b0df3163774166f7578a12b9880 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 00:55:33 -0400 Subject: [PATCH 18/54] ci: simplify and fix yaml --- .github/workflows/additional_testing.yml | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 8b1e1340..4be90dbf 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -3,19 +3,19 @@ on: push: env: - OS_TO_USE: ubuntu-24.04 - ARCH_TO_USE: x86_64 - CIBW_SYSTEM_TO_USE: manylinux - PYTHON_VERSION_TO_USE: cp313 - TESTSUITE_TO_USE: fast - ITERATIONS_TO_USE: 3 + OS: ubuntu-24.04 + ARCH: x86_64 + CIBW_SYSTEM: manylinux + PYTHON_VERSION: cp313 + TESTSUITE: fast + ITERATIONS: 3 jobs: build: - name: "Build wheel: ${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }}" - runs-on: ${{ env.OS_TO_USE }} + name: "Build wheel: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }}" + runs-on: ${{ env.OS }} steps: - name: Checkout DuckDB Python @@ -28,14 +28,14 @@ jobs: with: version: "0.8.16" enable-cache: false - cache-suffix: -${{ env.PYTHON_VERSION_TO_USE }}-${{ env.OS_TO_USE }} - python-version: ${{ env.PYTHON_VERSION_TO_USE }} + cache-suffix: -${{ env.PYTHON_VERSION }}-${{ env.OS }} + python-version: ${{ env.PYTHON_VERSION }} - name: Build wheel uses: pypa/cibuildwheel@v3.1 env: - CIBW_ARCHS: ${{ env.ARCH_TO_USE == 'amd64' && 'AMD64' || env.ARCH_TO_USE }} - CIBW_BUILD: ${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }} + CIBW_ARCHS: ${{ env.ARCH }} + CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} CIBW_TEST_SKIP: '*' # Platform-specific ccache installation commands CIBW_BEFORE_BUILD_LINUX: "" @@ -45,12 +45,12 @@ jobs: - name: Upload wheel uses: actions/upload-artifact@v4 with: - name: wheel-${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }} + name: wheel-${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} path: wheelhouse/ test: - name: 'Test: ${{ matrix.pytest_config.name }} - ${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }}' - runs-on: ${{ env.OS_TO_USE }} + name: 'Test: ${{ matrix.pytest_config.name }} - ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }}' + runs-on: ${{ env.OS }} needs: build strategy: fail-fast: false @@ -78,13 +78,13 @@ jobs: with: version: "0.8.16" enable-cache: false - cache-suffix: -${{ env.PYTHON_VERSION_TO_USE }}-${{ env.OS_TO_USE }} - python-version: ${{ env.PYTHON_VERSION_TO_USE }} + cache-suffix: -${{ env.PYTHON_VERSION }}-${{ env.OS }} + python-version: ${{ env.PYTHON_VERSION }} - name: Download wheel uses: actions/download-artifact@v4 with: - name: wheel-${{ env.PYTHON_VERSION_TO_USE }}-${{ env.CIBW_SYSTEM_TO_USE }}_${{ env.ARCH_TO_USE }} + name: wheel-${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} path: wheelhouse/ - name: Install dependencies From b432bb5815ad7d3ba4ad654e2e6e769f69f5db4d Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 00:56:48 -0400 Subject: [PATCH 19/54] ci: fix yaml --- .github/workflows/additional_testing.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 4be90dbf..062f172b 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -14,8 +14,8 @@ env: jobs: build: - name: "Build wheel: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }}" - runs-on: ${{ env.OS }} + name: "Build wheel: cp313-manylinux_x86_64" + runs-on: ubuntu-24.04 steps: - name: Checkout DuckDB Python @@ -49,8 +49,8 @@ jobs: path: wheelhouse/ test: - name: 'Test: ${{ matrix.pytest_config.name }} - ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }}' - runs-on: ${{ env.OS }} + name: 'Test: ${{ matrix.pytest_config.name }} - cp313-manylinux_x86_64' + runs-on: ubuntu-24.04 needs: build strategy: fail-fast: false From 8d016172d76958b3303c4f4fc82dc66fad3155e9 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 01:38:00 -0400 Subject: [PATCH 20/54] ci: initialize the venv --- .github/workflows/additional_testing.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 062f172b..cea9ff44 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -90,7 +90,8 @@ jobs: - name: Install dependencies shell: bash run: | - uv export --only-group test --no-emit-project --output-file pylock.toml + uv venv + uv export --only-group test --no-emit-project --output-file pylock.toml --quiet uv pip install -r pylock.toml uv pip install wheelhouse/*.whl From 64a05c722ef441f4a28391cf77abf9af219185d9 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 09:37:46 -0400 Subject: [PATCH 21/54] ci: Simplify and avoid editables --- .github/workflows/additional_testing.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index cea9ff44..80a246c6 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -68,11 +68,13 @@ jobs: iterations: 1 steps: - - name: Checkout DuckDB Python + - name: Checkout test files only uses: actions/checkout@v4 with: - fetch-depth: 0 - submodules: true + sparse-checkout: | + tests + pyproject.toml + sparse-checkout-cone-mode: false - uses: astral-sh/setup-uv@v6 with: @@ -91,9 +93,8 @@ jobs: shell: bash run: | uv venv - uv export --only-group test --no-emit-project --output-file pylock.toml --quiet - uv pip install -r pylock.toml - uv pip install wheelhouse/*.whl + uv pip install pytest pytest-xdist pytest-randomly pytest-run-parallel + uv pip install wheelhouse/*.whl --no-deps --force-reinstall - name: Run ${{ matrix.pytest_config.name }} tests shell: bash From 02a6c2b7aded98f1c09799123f9f7ab2f839d5cd Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 10:15:27 -0400 Subject: [PATCH 22/54] avoid the rebuild --- .github/workflows/additional_testing.yml | 26 +++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 80a246c6..32488c05 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -31,6 +31,11 @@ jobs: cache-suffix: -${{ env.PYTHON_VERSION }}-${{ env.OS }} python-version: ${{ env.PYTHON_VERSION }} + - name: Export test requirements + shell: bash + run: | + uv export --only-group test --no-emit-project --output-file test-requirements.txt --quiet + - name: Build wheel uses: pypa/cibuildwheel@v3.1 env: @@ -40,7 +45,13 @@ jobs: # Platform-specific ccache installation commands CIBW_BEFORE_BUILD_LINUX: "" CIBW_BEFORE_BUILD_MACOS: "" - CIBW_BEFORE_BUILD_WINDOWS: "" + CIBW_BEFORE_BUILD_WINDOWS: "" + + - name: Upload test requirements + uses: actions/upload-artifact@v4 + with: + name: test-requirements-${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} + path: test-requirements.txt - name: Upload wheel uses: actions/upload-artifact@v4 @@ -71,9 +82,7 @@ jobs: - name: Checkout test files only uses: actions/checkout@v4 with: - sparse-checkout: | - tests - pyproject.toml + sparse-checkout: tests sparse-checkout-cone-mode: false - uses: astral-sh/setup-uv@v6 @@ -89,11 +98,18 @@ jobs: name: wheel-${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} path: wheelhouse/ + - name: Download test requirements + uses: actions/download-artifact@v4 + with: + name: test-requirements-${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} + path: . + - name: Install dependencies shell: bash run: | uv venv - uv pip install pytest pytest-xdist pytest-randomly pytest-run-parallel + rm -f pyproject.toml # Remove any project metadata to prevent build attempts + uv pip install -r test-requirements.txt uv pip install wheelhouse/*.whl --no-deps --force-reinstall - name: Run ${{ matrix.pytest_config.name }} tests From 81144fa5006970a404b3bce097c72eff7bd98574 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 11:07:36 -0400 Subject: [PATCH 23/54] Simple install --- .github/workflows/additional_testing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 32488c05..6d44364c 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -88,7 +88,8 @@ jobs: - uses: astral-sh/setup-uv@v6 with: version: "0.8.16" - enable-cache: false + enable-cache: true + activate-environment: true cache-suffix: -${{ env.PYTHON_VERSION }}-${{ env.OS }} python-version: ${{ env.PYTHON_VERSION }} @@ -107,7 +108,6 @@ jobs: - name: Install dependencies shell: bash run: | - uv venv rm -f pyproject.toml # Remove any project metadata to prevent build attempts uv pip install -r test-requirements.txt uv pip install wheelhouse/*.whl --no-deps --force-reinstall From 9e840407019dbac01876b1def23d3322cf7160a9 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 11:31:45 -0400 Subject: [PATCH 24/54] ci: enable SCCACHE --- .github/workflows/additional_testing.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 6d44364c..caa55076 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -43,10 +43,20 @@ jobs: CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} CIBW_TEST_SKIP: '*' # Platform-specific ccache installation commands - CIBW_BEFORE_BUILD_LINUX: "" - CIBW_BEFORE_BUILD_MACOS: "" - CIBW_BEFORE_BUILD_WINDOWS: "" - + CIBW_BEFORE_BUILD_LINUX: > + if [ "$(uname -m)" = "aarch64" ]; then ARCH=aarch64; else ARCH=x86_64; fi && + curl -L https://github.com/mozilla/sccache/releases/download/v0.10.0/sccache-v0.10.0-${ARCH}-unknown-linux-musl.tar.gz | tar xz && + cp sccache-v0.10.0-${ARCH}-unknown-linux-musl/sccache /usr/bin && + sccache --show-stats + CIBW_BEFORE_BUILD_MACOS: brew install sccache + CIBW_BEFORE_BUILD_WINDOWS: > + del "C:\Strawberry\c\bin\ccache.exe" && + choco install sccache + SCCACHE_GHA_ENABLED: "on" + SCCACHE_C_CUSTOM_CACHE_BUSTER: ${{ env.PYTHON_VERSION }}-${{ env.OS }} + ACTIONS_CACHE_SERVICE_V2: "1" + CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER="" CMAKE_CXX_COMPILER_LAUNCHER="" CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" + CIBW_ENVIRONMENT_PASS: SCCACHE_GHA_ENABLED ACTIONS_RUNTIME_TOKEN ACTIONS_RESULTS_URL ACTIONS_CACHE_SERVICE_V2 SCCACHE_C_CUSTOM_CACHE_BUSTER PYTHON_GIL - name: Upload test requirements uses: actions/upload-artifact@v4 with: From 050b3fccd86fd1c3bdde1ab1e52ed4425f8ad1f3 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 11:35:02 -0400 Subject: [PATCH 25/54] ci: env vars for sccache --- .github/workflows/additional_testing.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index caa55076..1ba6425e 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -35,7 +35,12 @@ jobs: shell: bash run: | uv export --only-group test --no-emit-project --output-file test-requirements.txt --quiet - + - name: Configure Cache Env + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - name: Build wheel uses: pypa/cibuildwheel@v3.1 env: @@ -43,6 +48,10 @@ jobs: CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} CIBW_TEST_SKIP: '*' # Platform-specific ccache installation commands + CIBW_BEFORE_TEST: > + sccache --show-stats && + uv export --only-group test --no-emit-project --output-file pylock.toml --directory {project} --quiet && + uv pip install -r pylock.toml CIBW_BEFORE_BUILD_LINUX: > if [ "$(uname -m)" = "aarch64" ]; then ARCH=aarch64; else ARCH=x86_64; fi && curl -L https://github.com/mozilla/sccache/releases/download/v0.10.0/sccache-v0.10.0-${ARCH}-unknown-linux-musl.tar.gz | tar xz && From 431e05a119fd8c53641c6bcd96ca59d93ec34d35 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 11:55:55 -0400 Subject: [PATCH 26/54] try different --- .github/workflows/additional_testing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 1ba6425e..ea87722d 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -127,8 +127,8 @@ jobs: - name: Install dependencies shell: bash run: | - rm -f pyproject.toml # Remove any project metadata to prevent build attempts - uv pip install -r test-requirements.txt + uv sync --no-install-project + rm -f pyproject.toml # Remove project metadata to prevent build attempts uv pip install wheelhouse/*.whl --no-deps --force-reinstall - name: Run ${{ matrix.pytest_config.name }} tests From e591d9476a3cd8b0eb19e9e9aa515b05039eff53 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 12:13:22 -0400 Subject: [PATCH 27/54] ci: include pyproject.toml --- .github/workflows/additional_testing.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index ea87722d..5398a67f 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -101,7 +101,9 @@ jobs: - name: Checkout test files only uses: actions/checkout@v4 with: - sparse-checkout: tests + sparse-checkout: | + tests + pyproject.toml sparse-checkout-cone-mode: false - uses: astral-sh/setup-uv@v6 From bc60905f363655b0a28353185a05e1feee86e25f Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 12:19:42 -0400 Subject: [PATCH 28/54] try wheel first --- .github/workflows/additional_testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 5398a67f..d29ac375 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -129,9 +129,9 @@ jobs: - name: Install dependencies shell: bash run: | + uv pip install wheelhouse/*.whl --no-deps --force-reinstall uv sync --no-install-project rm -f pyproject.toml # Remove project metadata to prevent build attempts - uv pip install wheelhouse/*.whl --no-deps --force-reinstall - name: Run ${{ matrix.pytest_config.name }} tests shell: bash From 3f7d34ae30b6a8b43d039fdd96f8b0e5a95f0375 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 12:27:55 -0400 Subject: [PATCH 29/54] no-build-isolation --- .github/workflows/additional_testing.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index d29ac375..71f0eb62 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -34,6 +34,8 @@ jobs: - name: Export test requirements shell: bash run: | + ls -l + ls -l external uv export --only-group test --no-emit-project --output-file test-requirements.txt --quiet - name: Configure Cache Env uses: actions/github-script@v7 @@ -49,9 +51,10 @@ jobs: CIBW_TEST_SKIP: '*' # Platform-specific ccache installation commands CIBW_BEFORE_TEST: > - sccache --show-stats && + sccache --show-stats && uv export --only-group test --no-emit-project --output-file pylock.toml --directory {project} --quiet && uv pip install -r pylock.toml + CIBW_TEST_COMMAND: sccache --show-stats CIBW_BEFORE_BUILD_LINUX: > if [ "$(uname -m)" = "aarch64" ]; then ARCH=aarch64; else ARCH=x86_64; fi && curl -L https://github.com/mozilla/sccache/releases/download/v0.10.0/sccache-v0.10.0-${ARCH}-unknown-linux-musl.tar.gz | tar xz && @@ -64,7 +67,7 @@ jobs: SCCACHE_GHA_ENABLED: "on" SCCACHE_C_CUSTOM_CACHE_BUSTER: ${{ env.PYTHON_VERSION }}-${{ env.OS }} ACTIONS_CACHE_SERVICE_V2: "1" - CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER="" CMAKE_CXX_COMPILER_LAUNCHER="" CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" + CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER=sccache CMAKE_CXX_COMPILER_LAUNCHER=sccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" CIBW_ENVIRONMENT_PASS: SCCACHE_GHA_ENABLED ACTIONS_RUNTIME_TOKEN ACTIONS_RESULTS_URL ACTIONS_CACHE_SERVICE_V2 SCCACHE_C_CUSTOM_CACHE_BUSTER PYTHON_GIL - name: Upload test requirements uses: actions/upload-artifact@v4 @@ -130,7 +133,7 @@ jobs: shell: bash run: | uv pip install wheelhouse/*.whl --no-deps --force-reinstall - uv sync --no-install-project + uv sync --no-install-project --no-build-isolation rm -f pyproject.toml # Remove project metadata to prevent build attempts - name: Run ${{ matrix.pytest_config.name }} tests From 7f8816f9a452acea266d21391fcee6b9693e8302 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 12:47:37 -0400 Subject: [PATCH 30/54] ci: Try a ccache solution due to rate limiting --- .github/workflows/additional_testing.yml | 47 ++++++++++-------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 71f0eb62..52063418 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -24,6 +24,7 @@ jobs: fetch-depth: 0 submodules: true + - uses: astral-sh/setup-uv@v6 with: version: "0.8.16" @@ -31,44 +32,36 @@ jobs: cache-suffix: -${{ env.PYTHON_VERSION }}-${{ env.OS }} python-version: ${{ env.PYTHON_VERSION }} + - name: Cache ccache objects + uses: actions/cache@v4 + with: + path: ./wheelhouse/ccache + key: ccache-${{ env.PYTHON_VERSION }}-${{ env.OS }}-${{ hashFiles('**/*.cpp', '**/*.c', '**/*.h', '**/*.hpp') }} + restore-keys: | + ccache-${{ env.PYTHON_VERSION }}-${{ env.OS }}- + + - name: Export test requirements shell: bash run: | - ls -l - ls -l external uv export --only-group test --no-emit-project --output-file test-requirements.txt --quiet - - name: Configure Cache Env - uses: actions/github-script@v7 - with: - script: | - core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || ''); - core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Prepare ccache directory + shell: bash + run: mkdir -p ./wheelhouse/ccache + - name: Build wheel uses: pypa/cibuildwheel@v3.1 + with: + output-dir: wheelhouse env: CIBW_ARCHS: ${{ env.ARCH }} CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} CIBW_TEST_SKIP: '*' # Platform-specific ccache installation commands - CIBW_BEFORE_TEST: > - sccache --show-stats && - uv export --only-group test --no-emit-project --output-file pylock.toml --directory {project} --quiet && - uv pip install -r pylock.toml - CIBW_TEST_COMMAND: sccache --show-stats - CIBW_BEFORE_BUILD_LINUX: > - if [ "$(uname -m)" = "aarch64" ]; then ARCH=aarch64; else ARCH=x86_64; fi && - curl -L https://github.com/mozilla/sccache/releases/download/v0.10.0/sccache-v0.10.0-${ARCH}-unknown-linux-musl.tar.gz | tar xz && - cp sccache-v0.10.0-${ARCH}-unknown-linux-musl/sccache /usr/bin && - sccache --show-stats - CIBW_BEFORE_BUILD_MACOS: brew install sccache - CIBW_BEFORE_BUILD_WINDOWS: > - del "C:\Strawberry\c\bin\ccache.exe" && - choco install sccache - SCCACHE_GHA_ENABLED: "on" - SCCACHE_C_CUSTOM_CACHE_BUSTER: ${{ env.PYTHON_VERSION }}-${{ env.OS }} - ACTIONS_CACHE_SERVICE_V2: "1" - CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER=sccache CMAKE_CXX_COMPILER_LAUNCHER=sccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" - CIBW_ENVIRONMENT_PASS: SCCACHE_GHA_ENABLED ACTIONS_RUNTIME_TOKEN ACTIONS_RESULTS_URL ACTIONS_CACHE_SERVICE_V2 SCCACHE_C_CUSTOM_CACHE_BUSTER PYTHON_GIL + CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER=ccache CMAKE_CXX_COMPILER_LAUNCHER=ccache CCACHE_DIR={project}/wheelhouse/ccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" + CIBW_AFTER_BUILD: ccache -s + - name: Upload test requirements uses: actions/upload-artifact@v4 with: From 962727b9583579afaa1c420391e1ad99a9033fc4 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 12:51:01 -0400 Subject: [PATCH 31/54] "" not ccache --- .github/workflows/additional_testing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 52063418..865fff5b 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -36,7 +36,7 @@ jobs: uses: actions/cache@v4 with: path: ./wheelhouse/ccache - key: ccache-${{ env.PYTHON_VERSION }}-${{ env.OS }}-${{ hashFiles('**/*.cpp', '**/*.c', '**/*.h', '**/*.hpp') }} + key: ccache-${{ env.PYTHON_VERSION }}-${{ env.OS }} restore-keys: | ccache-${{ env.PYTHON_VERSION }}-${{ env.OS }}- @@ -59,7 +59,7 @@ jobs: CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} CIBW_TEST_SKIP: '*' # Platform-specific ccache installation commands - CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER=ccache CMAKE_CXX_COMPILER_LAUNCHER=ccache CCACHE_DIR={project}/wheelhouse/ccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" + CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER="" CMAKE_CXX_COMPILER_LAUNCHER="" CCACHE_DIR={project}/wheelhouse/ccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" CIBW_AFTER_BUILD: ccache -s - name: Upload test requirements From 6601b2da5410697661d536d71a95befccf0833b8 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 14:41:36 -0400 Subject: [PATCH 32/54] debug prints --- .github/workflows/additional_testing.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 865fff5b..aac25993 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -60,7 +60,7 @@ jobs: CIBW_TEST_SKIP: '*' # Platform-specific ccache installation commands CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER="" CMAKE_CXX_COMPILER_LAUNCHER="" CCACHE_DIR={project}/wheelhouse/ccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" - CIBW_AFTER_BUILD: ccache -s + CIBW_AFTER_BUILD: ccache -s && ls -la {project}/wheelhouse/ccache - name: Upload test requirements uses: actions/upload-artifact@v4 @@ -68,6 +68,14 @@ jobs: name: test-requirements-${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} path: test-requirements.txt + - name: Show ccache directory contents + shell: bash + run: | + echo "Ccache directory contents:" + ls -la ./wheelhouse/ccache/ || echo "No ccache directory found" + echo "Ccache directory size:" + du -sh ./wheelhouse/ccache/ || echo "No ccache directory found" + - name: Upload wheel uses: actions/upload-artifact@v4 with: From 83235508491899f3bd77b62696fa7a53efe725f4 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 15:05:44 -0400 Subject: [PATCH 33/54] ci shrink w --- .github/workflows/additional_testing.yml | 11 ++++++- src/duckdb_py/CMakeLists.txt | 38 ++++++++---------------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index aac25993..2975e7da 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -60,7 +60,7 @@ jobs: CIBW_TEST_SKIP: '*' # Platform-specific ccache installation commands CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER="" CMAKE_CXX_COMPILER_LAUNCHER="" CCACHE_DIR={project}/wheelhouse/ccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" - CIBW_AFTER_BUILD: ccache -s && ls -la {project}/wheelhouse/ccache + CIBW_AFTER_BUILD: ccache -s && ls -la {project}/wheelhouse/ccache && echo "=== CCACHE STATS ===" && ccache -s && echo "=== END CCACHE STATS ===" - name: Upload test requirements uses: actions/upload-artifact@v4 @@ -71,10 +71,19 @@ jobs: - name: Show ccache directory contents shell: bash run: | + echo "Wheelhouse contents:" + ls -la ./wheelhouse/ || echo "No wheelhouse directory found" + echo "" echo "Ccache directory contents:" ls -la ./wheelhouse/ccache/ || echo "No ccache directory found" + echo "" + echo "Ccache backup directory contents:" + ls -la ./wheelhouse/ccache-backup/ || echo "No ccache-backup directory found" + echo "" echo "Ccache directory size:" du -sh ./wheelhouse/ccache/ || echo "No ccache directory found" + echo "Ccache backup directory size:" + du -sh ./wheelhouse/ccache-backup/ || echo "No ccache-backup directory found" - name: Upload wheel uses: actions/upload-artifact@v4 diff --git a/src/duckdb_py/CMakeLists.txt b/src/duckdb_py/CMakeLists.txt index 2252ba29..dc2a1c4f 100644 --- a/src/duckdb_py/CMakeLists.txt +++ b/src/duckdb_py/CMakeLists.txt @@ -1,33 +1,19 @@ # this is used for clang-tidy checks -add_subdirectory(pyrelation) -add_subdirectory(pyexpression) -add_subdirectory(pybind11) -add_subdirectory(numpy) -add_subdirectory(native) -add_subdirectory(jupyter) -add_subdirectory(typing) -add_subdirectory(functional) -add_subdirectory(pyconnection) -add_subdirectory(common) -add_subdirectory(pandas) -add_subdirectory(arrow) +# add_subdirectory(pyrelation) +# add_subdirectory(pyexpression) +# add_subdirectory(pybind11) +# add_subdirectory(numpy) +# add_subdirectory(native) +# add_subdirectory(jupyter) +# add_subdirectory(typing) +# add_subdirectory(functional) +# add_subdirectory(pyconnection) +# add_subdirectory(common) +# add_subdirectory(pandas) +# add_subdirectory(arrow) add_library(python_src OBJECT - dataframe.cpp - duckdb_python.cpp - importer.cpp map.cpp - path_like.cpp - pyconnection.cpp - pyexpression.cpp - pyfilesystem.cpp - pyrelation.cpp - pyresult.cpp - pystatement.cpp - python_dependency.cpp - python_import_cache.cpp - python_replacement_scan.cpp - python_udf.cpp ) target_link_libraries(python_src PRIVATE _duckdb_dependencies) From 5ab762b7fca74e61508c7acf4593846776ab8527 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 15:13:04 -0400 Subject: [PATCH 34/54] ci: reduce cmakelists for ci testing --- CMakeLists.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9bc047d..7b05709a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,18 +64,6 @@ add_subdirectory(src/duckdb_py) pybind11_add_module(_duckdb $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ ) # add _duckdb_dependencies target_link_libraries(_duckdb PRIVATE _duckdb_dependencies) From e0b6cb0f7a8cc252841a05f04979e78acd1d3c64 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 15:21:35 -0400 Subject: [PATCH 35/54] ci: compile --- .github/workflows/additional_testing.yml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 2975e7da..9fa32573 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -50,7 +50,7 @@ jobs: shell: bash run: mkdir -p ./wheelhouse/ccache - - name: Build wheel + - name: Minimal build with ccache uses: pypa/cibuildwheel@v3.1 with: output-dir: wheelhouse @@ -58,9 +58,22 @@ jobs: CIBW_ARCHS: ${{ env.ARCH }} CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} CIBW_TEST_SKIP: '*' - # Platform-specific ccache installation commands - CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER="" CMAKE_CXX_COMPILER_LAUNCHER="" CCACHE_DIR={project}/wheelhouse/ccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" - CIBW_AFTER_BUILD: ccache -s && ls -la {project}/wheelhouse/ccache && echo "=== CCACHE STATS ===" && ccache -s && echo "=== END CCACHE STATS ===" + # Minimal build configuration + CIBW_ENVIRONMENT: > + CCACHE_DIR={project}/wheelhouse/ccache + CMAKE_BUILD_TYPE=MinSizeRel + CMAKE_BUILD_PARALLEL_LEVEL=1 + CMAKE_CXX_FLAGS="-O1 -DNDEBUG" + CMAKE_C_FLAGS="-O1 -DNDEBUG" + CFLAGS="-Wno-attributes" + CXXFLAGS="-Wno-attributes" + CIBW_BEFORE_BUILD: > + yum install -y ccache && + export PATH="/usr/lib64/ccache:$PATH" && + ccache --max-size=1G + CIBW_AFTER_BUILD: > + ls -la {project}/wheelhouse/ccache && + ccache -s && - name: Upload test requirements uses: actions/upload-artifact@v4 From 761a41eba079c542e0227fecd659b929c359003e Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 15:24:57 -0400 Subject: [PATCH 36/54] Try speeding up --- .github/workflows/additional_testing.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 9fa32573..06c8a895 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -58,7 +58,7 @@ jobs: CIBW_ARCHS: ${{ env.ARCH }} CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} CIBW_TEST_SKIP: '*' - # Minimal build configuration + # Minimal build configuration - disable most DuckDB features CIBW_ENVIRONMENT: > CCACHE_DIR={project}/wheelhouse/ccache CMAKE_BUILD_TYPE=MinSizeRel @@ -67,6 +67,16 @@ jobs: CMAKE_C_FLAGS="-O1 -DNDEBUG" CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" + CORE_EXTENSIONS="" + DISABLE_BUILTIN_EXTENSIONS=ON + BUILD_PARQUET_EXTENSION=OFF + BUILD_TPCH_EXTENSION=OFF + BUILD_FTS_EXTENSION=OFF + BUILD_HTTPFS_EXTENSION=OFF + BUILD_VISUALIZER_EXTENSION=OFF + BUILD_TPCDS_EXTENSION=OFF + BUILD_JSON_EXTENSION=OFF + BUILD_ICU_EXTENSION=OFF CIBW_BEFORE_BUILD: > yum install -y ccache && export PATH="/usr/lib64/ccache:$PATH" && From a856df21495f3000c465b6c39e9b049ff156e2e5 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 15:28:43 -0400 Subject: [PATCH 37/54] ci 123 --- .github/workflows/additional_testing.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 06c8a895..d42abbdd 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -67,16 +67,11 @@ jobs: CMAKE_C_FLAGS="-O1 -DNDEBUG" CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" - CORE_EXTENSIONS="" + BUILD_EXTENSIONS="" DISABLE_BUILTIN_EXTENSIONS=ON - BUILD_PARQUET_EXTENSION=OFF - BUILD_TPCH_EXTENSION=OFF - BUILD_FTS_EXTENSION=OFF - BUILD_HTTPFS_EXTENSION=OFF - BUILD_VISUALIZER_EXTENSION=OFF - BUILD_TPCDS_EXTENSION=OFF - BUILD_JSON_EXTENSION=OFF - BUILD_ICU_EXTENSION=OFF + BUILD_SHELL=OFF + BUILD_UNITTESTS=OFF + BUILD_BENCHMARKS=OFF CIBW_BEFORE_BUILD: > yum install -y ccache && export PATH="/usr/lib64/ccache:$PATH" && From ab0c7e4c29f237d4837f5b9977ba8bddd23378b5 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 15:36:01 -0400 Subject: [PATCH 38/54] add a minimal build option --- .github/workflows/additional_testing.yml | 8 ++------ pyproject.toml | 12 ++++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index d42abbdd..195fbbd2 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -58,20 +58,16 @@ jobs: CIBW_ARCHS: ${{ env.ARCH }} CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} CIBW_TEST_SKIP: '*' - # Minimal build configuration - disable most DuckDB features + # Minimal build configuration - use pyproject.toml override CIBW_ENVIRONMENT: > CCACHE_DIR={project}/wheelhouse/ccache + CI_MINIMAL_BUILD=true CMAKE_BUILD_TYPE=MinSizeRel CMAKE_BUILD_PARALLEL_LEVEL=1 CMAKE_CXX_FLAGS="-O1 -DNDEBUG" CMAKE_C_FLAGS="-O1 -DNDEBUG" CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" - BUILD_EXTENSIONS="" - DISABLE_BUILTIN_EXTENSIONS=ON - BUILD_SHELL=OFF - BUILD_UNITTESTS=OFF - BUILD_BENCHMARKS=OFF CIBW_BEFORE_BUILD: > yum install -y ccache && export PATH="/usr/lib64/ccache:$PATH" && diff --git a/pyproject.toml b/pyproject.toml index d2a20f53..9326026c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -123,6 +123,18 @@ if.env.COVERAGE = false inherit.cmake.define = "append" cmake.define.DISABLE_UNITY = "1" +# Override: CI minimal build - disable all extensions +[[tool.scikit-build.overrides]] +if.env.CI_MINIMAL_BUILD = true +inherit.cmake.define = "replace" +cmake.define.CORE_EXTENSIONS = "" +cmake.define.BUILD_EXTENSIONS = "" +cmake.define.DISABLE_BUILTIN_EXTENSIONS = "ON" +cmake.define.BUILD_SHELL = "OFF" +cmake.define.BUILD_UNITTESTS = "OFF" +cmake.define.BUILD_BENCHMARKS = "OFF" +cmake.define.DISABLE_UNITY = "ON" + [tool.scikit-build.sdist] include = [ "README.md", From b845777882e93900ce17505d2f0613c9ecdc11b1 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 15:38:24 -0400 Subject: [PATCH 39/54] ci --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9326026c..d60aacb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,7 +126,7 @@ cmake.define.DISABLE_UNITY = "1" # Override: CI minimal build - disable all extensions [[tool.scikit-build.overrides]] if.env.CI_MINIMAL_BUILD = true -inherit.cmake.define = "replace" +inherit.cmake.define = "none" cmake.define.CORE_EXTENSIONS = "" cmake.define.BUILD_EXTENSIONS = "" cmake.define.DISABLE_BUILTIN_EXTENSIONS = "ON" From a3f9c8fe949bf3539871aaa576603f712b593212 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 15:41:15 -0400 Subject: [PATCH 40/54] DISABLE_UNITY --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d60aacb0..d97a5b45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -133,7 +133,6 @@ cmake.define.DISABLE_BUILTIN_EXTENSIONS = "ON" cmake.define.BUILD_SHELL = "OFF" cmake.define.BUILD_UNITTESTS = "OFF" cmake.define.BUILD_BENCHMARKS = "OFF" -cmake.define.DISABLE_UNITY = "ON" [tool.scikit-build.sdist] include = [ From 7ad0448d048251261389274ab672b3af49ab236f Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 15:44:14 -0400 Subject: [PATCH 41/54] revert --- CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b05709a..a9bc047d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,18 @@ add_subdirectory(src/duckdb_py) pybind11_add_module(_duckdb $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ ) # add _duckdb_dependencies target_link_libraries(_duckdb PRIVATE _duckdb_dependencies) From 74c626b63009c1600dfe317ccf579f3446c6583b Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 21:14:08 -0400 Subject: [PATCH 42/54] ci: right dir --- .github/workflows/additional_testing.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 195fbbd2..9484bf73 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -57,10 +57,13 @@ jobs: env: CIBW_ARCHS: ${{ env.ARCH }} CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} - CIBW_TEST_SKIP: '*' + CIBW_BEFORE_ALL: > + mkdir -p /output/ccache + CIBW_TEST_COMMAND: > + echo "ccache stats:" && ccache -s # Minimal build configuration - use pyproject.toml override CIBW_ENVIRONMENT: > - CCACHE_DIR={project}/wheelhouse/ccache + CCACHE_DIR=/output/ccache CI_MINIMAL_BUILD=true CMAKE_BUILD_TYPE=MinSizeRel CMAKE_BUILD_PARALLEL_LEVEL=1 From c02a17d6466b705fa7b87d34493ed8d2cf1d41fa Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 21:17:11 -0400 Subject: [PATCH 43/54] revert --- src/duckdb_py/CMakeLists.txt | 38 ++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/duckdb_py/CMakeLists.txt b/src/duckdb_py/CMakeLists.txt index dc2a1c4f..2252ba29 100644 --- a/src/duckdb_py/CMakeLists.txt +++ b/src/duckdb_py/CMakeLists.txt @@ -1,19 +1,33 @@ # this is used for clang-tidy checks -# add_subdirectory(pyrelation) -# add_subdirectory(pyexpression) -# add_subdirectory(pybind11) -# add_subdirectory(numpy) -# add_subdirectory(native) -# add_subdirectory(jupyter) -# add_subdirectory(typing) -# add_subdirectory(functional) -# add_subdirectory(pyconnection) -# add_subdirectory(common) -# add_subdirectory(pandas) -# add_subdirectory(arrow) +add_subdirectory(pyrelation) +add_subdirectory(pyexpression) +add_subdirectory(pybind11) +add_subdirectory(numpy) +add_subdirectory(native) +add_subdirectory(jupyter) +add_subdirectory(typing) +add_subdirectory(functional) +add_subdirectory(pyconnection) +add_subdirectory(common) +add_subdirectory(pandas) +add_subdirectory(arrow) add_library(python_src OBJECT + dataframe.cpp + duckdb_python.cpp + importer.cpp map.cpp + path_like.cpp + pyconnection.cpp + pyexpression.cpp + pyfilesystem.cpp + pyrelation.cpp + pyresult.cpp + pystatement.cpp + python_dependency.cpp + python_import_cache.cpp + python_replacement_scan.cpp + python_udf.cpp ) target_link_libraries(python_src PRIVATE _duckdb_dependencies) From 65452043d44df40838d91c727e9d9be2c7d20f3c Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 21:56:07 -0400 Subject: [PATCH 44/54] ci: use a single key --- .github/workflows/additional_testing.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 9484bf73..b13223d5 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -37,9 +37,6 @@ jobs: with: path: ./wheelhouse/ccache key: ccache-${{ env.PYTHON_VERSION }}-${{ env.OS }} - restore-keys: | - ccache-${{ env.PYTHON_VERSION }}-${{ env.OS }}- - - name: Export test requirements shell: bash From 1871990823e5dc358d6a0f8bccf021e49094a3bb Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 22:00:58 -0400 Subject: [PATCH 45/54] back to sccache --- .github/workflows/additional_testing.yml | 84 +++++++++--------------- 1 file changed, 30 insertions(+), 54 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index b13223d5..71f0eb62 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -24,7 +24,6 @@ jobs: fetch-depth: 0 submodules: true - - uses: astral-sh/setup-uv@v6 with: version: "0.8.16" @@ -32,73 +31,50 @@ jobs: cache-suffix: -${{ env.PYTHON_VERSION }}-${{ env.OS }} python-version: ${{ env.PYTHON_VERSION }} - - name: Cache ccache objects - uses: actions/cache@v4 - with: - path: ./wheelhouse/ccache - key: ccache-${{ env.PYTHON_VERSION }}-${{ env.OS }} - - name: Export test requirements shell: bash run: | + ls -l + ls -l external uv export --only-group test --no-emit-project --output-file test-requirements.txt --quiet - - - name: Prepare ccache directory - shell: bash - run: mkdir -p ./wheelhouse/ccache - - - name: Minimal build with ccache - uses: pypa/cibuildwheel@v3.1 + - name: Configure Cache Env + uses: actions/github-script@v7 with: - output-dir: wheelhouse + script: | + core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + - name: Build wheel + uses: pypa/cibuildwheel@v3.1 env: CIBW_ARCHS: ${{ env.ARCH }} CIBW_BUILD: ${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} - CIBW_BEFORE_ALL: > - mkdir -p /output/ccache - CIBW_TEST_COMMAND: > - echo "ccache stats:" && ccache -s - # Minimal build configuration - use pyproject.toml override - CIBW_ENVIRONMENT: > - CCACHE_DIR=/output/ccache - CI_MINIMAL_BUILD=true - CMAKE_BUILD_TYPE=MinSizeRel - CMAKE_BUILD_PARALLEL_LEVEL=1 - CMAKE_CXX_FLAGS="-O1 -DNDEBUG" - CMAKE_C_FLAGS="-O1 -DNDEBUG" - CFLAGS="-Wno-attributes" - CXXFLAGS="-Wno-attributes" - CIBW_BEFORE_BUILD: > - yum install -y ccache && - export PATH="/usr/lib64/ccache:$PATH" && - ccache --max-size=1G - CIBW_AFTER_BUILD: > - ls -la {project}/wheelhouse/ccache && - ccache -s && - + CIBW_TEST_SKIP: '*' + # Platform-specific ccache installation commands + CIBW_BEFORE_TEST: > + sccache --show-stats && + uv export --only-group test --no-emit-project --output-file pylock.toml --directory {project} --quiet && + uv pip install -r pylock.toml + CIBW_TEST_COMMAND: sccache --show-stats + CIBW_BEFORE_BUILD_LINUX: > + if [ "$(uname -m)" = "aarch64" ]; then ARCH=aarch64; else ARCH=x86_64; fi && + curl -L https://github.com/mozilla/sccache/releases/download/v0.10.0/sccache-v0.10.0-${ARCH}-unknown-linux-musl.tar.gz | tar xz && + cp sccache-v0.10.0-${ARCH}-unknown-linux-musl/sccache /usr/bin && + sccache --show-stats + CIBW_BEFORE_BUILD_MACOS: brew install sccache + CIBW_BEFORE_BUILD_WINDOWS: > + del "C:\Strawberry\c\bin\ccache.exe" && + choco install sccache + SCCACHE_GHA_ENABLED: "on" + SCCACHE_C_CUSTOM_CACHE_BUSTER: ${{ env.PYTHON_VERSION }}-${{ env.OS }} + ACTIONS_CACHE_SERVICE_V2: "1" + CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER=sccache CMAKE_CXX_COMPILER_LAUNCHER=sccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" + CIBW_ENVIRONMENT_PASS: SCCACHE_GHA_ENABLED ACTIONS_RUNTIME_TOKEN ACTIONS_RESULTS_URL ACTIONS_CACHE_SERVICE_V2 SCCACHE_C_CUSTOM_CACHE_BUSTER PYTHON_GIL - name: Upload test requirements uses: actions/upload-artifact@v4 with: name: test-requirements-${{ env.PYTHON_VERSION }}-${{ env.CIBW_SYSTEM }}_${{ env.ARCH }} path: test-requirements.txt - - name: Show ccache directory contents - shell: bash - run: | - echo "Wheelhouse contents:" - ls -la ./wheelhouse/ || echo "No wheelhouse directory found" - echo "" - echo "Ccache directory contents:" - ls -la ./wheelhouse/ccache/ || echo "No ccache directory found" - echo "" - echo "Ccache backup directory contents:" - ls -la ./wheelhouse/ccache-backup/ || echo "No ccache-backup directory found" - echo "" - echo "Ccache directory size:" - du -sh ./wheelhouse/ccache/ || echo "No ccache directory found" - echo "Ccache backup directory size:" - du -sh ./wheelhouse/ccache-backup/ || echo "No ccache-backup directory found" - - name: Upload wheel uses: actions/upload-artifact@v4 with: From ac38fd0d3797dd25a9735479c4f18e33c0e25115 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 22:03:23 -0400 Subject: [PATCH 46/54] ci set "" --- .github/workflows/additional_testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 71f0eb62..5ac9e5c3 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -67,7 +67,7 @@ jobs: SCCACHE_GHA_ENABLED: "on" SCCACHE_C_CUSTOM_CACHE_BUSTER: ${{ env.PYTHON_VERSION }}-${{ env.OS }} ACTIONS_CACHE_SERVICE_V2: "1" - CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER=sccache CMAKE_CXX_COMPILER_LAUNCHER=sccache CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" + CIBW_ENVIRONMENT: CMAKE_C_COMPILER_LAUNCHER="" CMAKE_CXX_COMPILER_LAUNCHER="" CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" CIBW_ENVIRONMENT_PASS: SCCACHE_GHA_ENABLED ACTIONS_RUNTIME_TOKEN ACTIONS_RESULTS_URL ACTIONS_CACHE_SERVICE_V2 SCCACHE_C_CUSTOM_CACHE_BUSTER PYTHON_GIL - name: Upload test requirements uses: actions/upload-artifact@v4 From a5cd5673761d17ec6103e7444bd9a008bc43b1b7 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 22:11:59 -0400 Subject: [PATCH 47/54] ci: testing --- .github/workflows/additional_testing.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 5ac9e5c3..41495dcd 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -106,7 +106,6 @@ jobs: with: sparse-checkout: | tests - pyproject.toml sparse-checkout-cone-mode: false - uses: astral-sh/setup-uv@v6 @@ -133,8 +132,7 @@ jobs: shell: bash run: | uv pip install wheelhouse/*.whl --no-deps --force-reinstall - uv sync --no-install-project --no-build-isolation - rm -f pyproject.toml # Remove project metadata to prevent build attempts + uv pip install -r test-requirements.txt - name: Run ${{ matrix.pytest_config.name }} tests shell: bash From 68f24824efb785a8465d61e418b479b221582e53 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 23:31:44 -0400 Subject: [PATCH 48/54] ci: difference install --- .github/workflows/additional_testing.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 41495dcd..e245bb8a 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -101,13 +101,6 @@ jobs: iterations: 1 steps: - - name: Checkout test files only - uses: actions/checkout@v4 - with: - sparse-checkout: | - tests - sparse-checkout-cone-mode: false - - uses: astral-sh/setup-uv@v6 with: version: "0.8.16" @@ -116,6 +109,14 @@ jobs: cache-suffix: -${{ env.PYTHON_VERSION }}-${{ env.OS }} python-version: ${{ env.PYTHON_VERSION }} + - name: Checkout test files only + uses: actions/checkout@v4 + with: + sparse-checkout: | + tests + pyproject.toml + sparse-checkout-cone-mode: false + - name: Download wheel uses: actions/download-artifact@v4 with: @@ -131,8 +132,8 @@ jobs: - name: Install dependencies shell: bash run: | - uv pip install wheelhouse/*.whl --no-deps --force-reinstall - uv pip install -r test-requirements.txt + uv sync --no-install-project + uv pip install wheelhouse/*.whl - name: Run ${{ matrix.pytest_config.name }} tests shell: bash From 10d728efb9b20d3c5442030e71592a1e81f7f557 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 23:42:56 -0400 Subject: [PATCH 49/54] reduce test size --- .github/workflows/packaging_wheels.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/packaging_wheels.yml b/.github/workflows/packaging_wheels.yml index 6616453e..df4edfab 100644 --- a/.github/workflows/packaging_wheels.yml +++ b/.github/workflows/packaging_wheels.yml @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - python: [ cp39, cp310, cp311, cp312, cp313, cp314, cp314t ] + python: [cp313, cp314t ] # cp39, cp310, cp311, cp312, cp313, cp314, platform: - { os: windows-2025, arch: amd64, cibw_system: win } - { os: ubuntu-24.04, arch: x86_64, cibw_system: manylinux } @@ -41,10 +41,13 @@ jobs: minimal: - ${{ inputs.minimal }} exclude: + - { minimal: true, python: cp39 } - { minimal: true, python: cp310 } - { minimal: true, python: cp311 } - { minimal: true, python: cp312 } - - { minimal: true, platform: { arch: universal2 } } + - { minimal: true, python: cp313 } + - { minimal: true, platform: { os: macos-15 } } + - { minimal: true, platform: { os: macos-13 } } # Windows+cp314t disabled due to test failures in CI. # TODO: Diagnose why tests fail (access violations) in some configurations - { python: cp314t, platform: { os: windows-2025 } } From 415fc9e6de180cca308ab8334e720bbb79803253 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Thu, 18 Sep 2025 23:44:42 -0400 Subject: [PATCH 50/54] --no-build-isolation --- .github/workflows/additional_testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index e245bb8a..3ae748be 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -132,7 +132,7 @@ jobs: - name: Install dependencies shell: bash run: | - uv sync --no-install-project + uv sync --no-install-project --no-build-isolation uv pip install wheelhouse/*.whl - name: Run ${{ matrix.pytest_config.name }} tests From 3c26205edb84ad0a0b8148d0f13385b63ef8b2dc Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Fri, 19 Sep 2025 00:03:45 -0400 Subject: [PATCH 51/54] ci t3 --- .github/workflows/additional_testing.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 3ae748be..40618dfe 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -111,11 +111,6 @@ jobs: - name: Checkout test files only uses: actions/checkout@v4 - with: - sparse-checkout: | - tests - pyproject.toml - sparse-checkout-cone-mode: false - name: Download wheel uses: actions/download-artifact@v4 @@ -132,7 +127,7 @@ jobs: - name: Install dependencies shell: bash run: | - uv sync --no-install-project --no-build-isolation + uv sync --no-install-project uv pip install wheelhouse/*.whl - name: Run ${{ matrix.pytest_config.name }} tests From f65f97372522891814d3e235e4c5d9075ddbe75b Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Fri, 19 Sep 2025 00:10:24 -0400 Subject: [PATCH 52/54] ffetch-depth: 0 --- .github/workflows/additional_testing.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index 40618dfe..b7b755f2 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -111,6 +111,8 @@ jobs: - name: Checkout test files only uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Download wheel uses: actions/download-artifact@v4 From ede993b70458883c2ecc05ff79f56348cd23cf95 Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Fri, 19 Sep 2025 00:35:58 -0400 Subject: [PATCH 53/54] ci --- .github/workflows/additional_testing.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index b7b755f2..cd43f088 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -113,6 +113,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 + submodules: true - name: Download wheel uses: actions/download-artifact@v4 From 4aa4ba0a5581bba39588c5e550bd428577d4528d Mon Sep 17 00:00:00 2001 From: "paul@iqmo.com" Date: Fri, 19 Sep 2025 00:44:44 -0400 Subject: [PATCH 54/54] test uv --- .github/workflows/additional_testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/additional_testing.yml b/.github/workflows/additional_testing.yml index cd43f088..ba3ce640 100644 --- a/.github/workflows/additional_testing.yml +++ b/.github/workflows/additional_testing.yml @@ -145,7 +145,7 @@ jobs: echo "" echo "${{ matrix.pytest_config.name }} Run $i/$ITERATIONS:" echo "--------" - uv run pytest $PYTEST_ARGS "$TEST_TARGET" --durations=5 + pytest $PYTEST_ARGS "$TEST_TARGET" --durations=5 if [ $? -ne 0 ]; then echo "${{ matrix.pytest_config.name }} Run $i failed!" else