@@ -126,17 +126,25 @@ def test_drop_catalog_motherduck(make_mocked_engine_adapter: t.Callable) -> None
126126 assert to_sql_calls (adapter ) == ['DROP DATABASE IF EXISTS "foo" CASCADE' ]
127127
128128
129- def test_ducklake_partitioning (adapter : EngineAdapter , duck_conn , tmp_path ):
129+ @pytest .fixture
130+ def ducklake_conn (duck_conn ):
131+ # Don't call install_extension here: on Windows it fails with "Access is denied"
132+ # once an earlier test in this process has loaded DuckLake. LOAD auto-installs it
133+ # when missing, and Windows CI pre-installs it before pytest.
134+ duck_conn .load_extension ("ducklake" )
135+ return duck_conn
136+
137+
138+ @pytest .mark .xdist_group ("ducklake_extension" )
139+ def test_ducklake_partitioning (adapter : EngineAdapter , ducklake_conn , tmp_path ):
130140 catalog = "a_ducklake_db"
131141
132- duck_conn .install_extension ("ducklake" )
133- duck_conn .load_extension ("ducklake" )
134- duck_conn .execute (
142+ ducklake_conn .execute (
135143 f"ATTACH 'ducklake:{ tmp_path } /{ catalog } .ducklake' AS { catalog } (DATA_PATH '{ tmp_path } ');"
136144 )
137145
138146 # no partitions on catalog creation
139- partition_info = duck_conn .execute (
147+ partition_info = ducklake_conn .execute (
140148 f"SELECT * FROM __ducklake_metadata_{ catalog } .main.ducklake_partition_info"
141149 ).fetchdf ()
142150 assert partition_info .empty
@@ -150,31 +158,30 @@ def test_ducklake_partitioning(adapter: EngineAdapter, duck_conn, tmp_path):
150158 )
151159
152160 # 1 partition after table creation
153- partition_info = duck_conn .execute (
161+ partition_info = ducklake_conn .execute (
154162 f"SELECT * FROM __ducklake_metadata_{ catalog } .main.ducklake_partition_info"
155163 ).fetchdf ()
156164 assert partition_info .shape [0 ] == 1
157165
158166
159- def test_drop_table_ducklake_no_cascade (adapter : EngineAdapter , duck_conn , tmp_path ):
167+ @pytest .mark .xdist_group ("ducklake_extension" )
168+ def test_drop_table_ducklake_no_cascade (adapter : EngineAdapter , ducklake_conn , tmp_path ):
160169 # DuckLake does not implement DROP TABLE/VIEW ... CASCADE, so the adapter must
161170 # omit CASCADE for objects in a DuckLake catalog while keeping it for native catalogs.
162171 catalog = "a_ducklake_db"
163172
164- duck_conn .install_extension ("ducklake" )
165- duck_conn .load_extension ("ducklake" )
166- duck_conn .execute (
173+ ducklake_conn .execute (
167174 f"ATTACH 'ducklake:{ tmp_path } /{ catalog } .ducklake' AS { catalog } (DATA_PATH '{ tmp_path } ');"
168175 )
169176
170- duck_conn .execute (f"CREATE SCHEMA { catalog } .phys" )
171- duck_conn .execute (f"CREATE SCHEMA { catalog } .virt" )
172- duck_conn .execute (f"CREATE TABLE { catalog } .phys.t (i INTEGER)" )
173- duck_conn .execute (f"CREATE VIEW { catalog } .virt.v AS SELECT * FROM { catalog } .phys.t" )
177+ ducklake_conn .execute (f"CREATE SCHEMA { catalog } .phys" )
178+ ducklake_conn .execute (f"CREATE SCHEMA { catalog } .virt" )
179+ ducklake_conn .execute (f"CREATE TABLE { catalog } .phys.t (i INTEGER)" )
180+ ducklake_conn .execute (f"CREATE VIEW { catalog } .virt.v AS SELECT * FROM { catalog } .phys.t" )
174181
175182 # native catalog, cascade is passed through
176- duck_conn .execute ("CREATE TABLE memory.main.native_t (i INTEGER)" )
177- duck_conn .execute ("CREATE VIEW memory.main.native_v AS SELECT * FROM memory.main.native_t" )
183+ ducklake_conn .execute ("CREATE TABLE memory.main.native_t (i INTEGER)" )
184+ ducklake_conn .execute ("CREATE VIEW memory.main.native_v AS SELECT * FROM memory.main.native_t" )
178185
179186 adapter .drop_table (f"{ catalog } .phys.t" , cascade = True )
180187 adapter .drop_view (f"{ catalog } .virt.v" , cascade = True )
@@ -187,19 +194,18 @@ def test_drop_table_ducklake_no_cascade(adapter: EngineAdapter, duck_conn, tmp_p
187194 assert not adapter .table_exists ("memory.main.native_v" )
188195
189196
197+ @pytest .mark .xdist_group ("ducklake_extension" )
190198def test_drop_table_ducklake_no_cascade_mixed_case_alias (
191- adapter : EngineAdapter , duck_conn , tmp_path
199+ adapter : EngineAdapter , ducklake_conn , tmp_path
192200):
193201 # Catalog aliases keep their case in duckdb_databases(), but SQLMesh normalizes
194202 # table names to lowercase, so the catalog type lookup must be case-insensitive.
195- duck_conn .install_extension ("ducklake" )
196- duck_conn .load_extension ("ducklake" )
197- duck_conn .execute (
203+ ducklake_conn .execute (
198204 f"ATTACH 'ducklake:{ tmp_path } /my_lake.ducklake' AS \" MyLake\" (DATA_PATH '{ tmp_path } ');"
199205 )
200- duck_conn .execute ("CREATE SCHEMA MyLake.phys" )
201- duck_conn .execute ("CREATE TABLE MyLake.phys.t (i INTEGER)" )
202- duck_conn .execute ("CREATE VIEW MyLake.phys.v AS SELECT * FROM MyLake.phys.t" )
206+ ducklake_conn .execute ("CREATE SCHEMA MyLake.phys" )
207+ ducklake_conn .execute ("CREATE TABLE MyLake.phys.t (i INTEGER)" )
208+ ducklake_conn .execute ("CREATE VIEW MyLake.phys.v AS SELECT * FROM MyLake.phys.t" )
203209
204210 adapter .drop_table ("mylake.phys.t" , cascade = True )
205211 adapter .drop_view ("mylake.phys.v" , cascade = True )
0 commit comments