33from __future__ import annotations
44
55import json
6- import sqlite3
76from typing import TYPE_CHECKING
87
98import pytest
109
1110from qcodes .dataset import (
1211 get_db_overview ,
13- initialise_or_create_database_at ,
1412 load_or_create_experiment ,
1513 new_data_set ,
1614)
1715from qcodes .dataset .descriptions .dependencies import InterDependencies_
16+ from qcodes .dataset .sqlite .connection import path_to_dbfile
1817from qcodes .dataset .sqlite .database import connect
1918from qcodes .dataset .sqlite .db_overview import (
2019 _format_timestamp ,
2524if TYPE_CHECKING :
2625 from pathlib import Path
2726
27+ from qcodes .dataset .sqlite .connection import AtomicConnection
2828
29- def _make_db_with_runs (
30- db_path : str ,
29+
30+ @pytest .fixture (name = "db_conn" )
31+ def _db_conn (tmp_path : Path , request : pytest .FixtureRequest ) -> AtomicConnection :
32+ """Connection to a fresh temporary database.
33+
34+ An explicit connection object is used rather than
35+ ``initialise_or_create_database_at`` so that the global QCoDeS config is
36+ left untouched. The connection is closed through a finalizer so that it is
37+ cleaned up even if the test fails.
38+ """
39+ conn = connect (str (tmp_path / "overview.db" ))
40+ request .addfinalizer (conn .close )
41+ return conn
42+
43+
44+ def _create_runs (
45+ conn : AtomicConnection ,
46+ * ,
3147 n_runs : int = 1 ,
3248 n_points : int = 10 ,
3349 experiment_name : str = "test_exp" ,
3450 sample_name : str = "test_sample" ,
3551) -> None :
36- """Create a database at ``db_path`` with ``n_runs`` simple numeric runs."""
37- initialise_or_create_database_at (db_path )
38- load_or_create_experiment (experiment_name , sample_name = sample_name )
52+ """Create ``n_runs`` simple numeric runs on ``conn``."""
53+ exp = load_or_create_experiment (experiment_name , sample_name = sample_name , conn = conn )
3954 p_x = ParamSpecBase ("x" , "numeric" )
4055 p_y = ParamSpecBase ("y" , "numeric" )
4156 interdeps = InterDependencies_ (dependencies = {p_y : (p_x ,)})
4257
4358 for r in range (n_runs ):
44- ds = new_data_set (f"run_{ r + 1 } " )
59+ ds = new_data_set (f"run_{ r + 1 } " , exp_id = exp . exp_id , conn = conn )
4560 ds .set_interdependencies (interdeps )
4661 ds .mark_started ()
4762 for i in range (n_points ):
4863 ds .add_results ([{p_x .name : float (i ), p_y .name : float (i ** 2 )}])
4964 ds .mark_completed ()
50- ds .conn .close ()
5165
5266
5367def test_records_from_run_description () -> None :
@@ -77,11 +91,10 @@ def test_format_timestamp() -> None:
7791 assert time .count (":" ) == 2
7892
7993
80- def test_get_db_overview_basic_fields (tmp_path : Path ) -> None :
81- db_path = str (tmp_path / "basic.db" )
82- _make_db_with_runs (db_path , n_runs = 2 )
94+ def test_get_db_overview_basic_fields (db_conn : AtomicConnection ) -> None :
95+ _create_runs (db_conn , n_runs = 2 )
8396
84- overview = get_db_overview (db_path )
97+ overview = get_db_overview (path_to_dbfile ( db_conn ) )
8598
8699 assert set (overview .keys ()) == {1 , 2 }
87100 for run_id , info in overview .items ():
@@ -94,109 +107,90 @@ def test_get_db_overview_basic_fields(tmp_path: Path) -> None:
94107 assert info ["completed_date" ] and info ["completed_time" ]
95108
96109
97- def test_get_db_overview_counts_result_rows (tmp_path : Path ) -> None :
98- db_path = str (tmp_path / "counts.db" )
99- _make_db_with_runs (db_path , n_runs = 3 , n_points = 10 )
110+ def test_get_db_overview_counts_result_rows (db_conn : AtomicConnection ) -> None :
111+ _create_runs (db_conn , n_runs = 3 , n_points = 10 )
100112
101- overview = get_db_overview (db_path )
113+ overview = get_db_overview (conn = db_conn )
102114
103- conn = sqlite3 .connect (db_path )
104- try :
105- for run_id , info in overview .items ():
106- (table_name ,) = conn .execute (
107- "SELECT result_table_name FROM runs WHERE run_id=?" , (run_id ,)
108- ).fetchone ()
109- (actual ,) = conn .execute (f'SELECT COUNT(*) FROM "{ table_name } "' ).fetchone ()
110- assert info ["records" ] == actual == 10
111- finally :
112- conn .close ()
115+ for run_id , info in overview .items ():
116+ (table_name ,) = db_conn .execute (
117+ "SELECT result_table_name FROM runs WHERE run_id=?" , (run_id ,)
118+ ).fetchone ()
119+ (actual ,) = db_conn .execute (f'SELECT COUNT(*) FROM "{ table_name } "' ).fetchone ()
120+ assert info ["records" ] == actual == 10
113121
114122
115- def test_get_db_overview_incremental (tmp_path : Path ) -> None :
116- db_path = str ( tmp_path / "incremental.db" )
117- _make_db_with_runs ( db_path , n_runs = 2 )
123+ def test_get_db_overview_incremental (db_conn : AtomicConnection ) -> None :
124+ _create_runs ( db_conn , n_runs = 2 )
125+ path = path_to_dbfile ( db_conn )
118126
119- assert set (get_db_overview (db_path ).keys ()) == {1 , 2 }
120- assert get_db_overview (db_path , start_run_id = 2 ) == {}
127+ assert set (get_db_overview (path ).keys ()) == {1 , 2 }
128+ assert get_db_overview (path , start_run_id = 2 ) == {}
121129
122- _make_db_with_runs ( db_path , n_runs = 1 , experiment_name = "test_exp2" , sample_name = "s2" )
130+ _create_runs ( db_conn , n_runs = 1 , experiment_name = "test_exp2" , sample_name = "s2" )
123131
124- incremental = get_db_overview (db_path , start_run_id = 2 )
132+ incremental = get_db_overview (path , start_run_id = 2 )
125133 assert set (incremental .keys ()) == {3 }
126134 assert incremental [3 ]["experiment" ] == "test_exp2"
127135
128136
129- def test_get_db_overview_extra_columns (tmp_path : Path ) -> None :
130- db_path = str (tmp_path / "extra.db" )
131- initialise_or_create_database_at (db_path )
132- load_or_create_experiment ("exp" , sample_name = "sample" )
137+ def test_get_db_overview_extra_columns (db_conn : AtomicConnection ) -> None :
138+ exp = load_or_create_experiment ("exp" , sample_name = "sample" , conn = db_conn )
133139 p_x = ParamSpecBase ("x" , "numeric" )
134140 p_y = ParamSpecBase ("y" , "numeric" )
135141 interdeps = InterDependencies_ (dependencies = {p_y : (p_x ,)})
136- ds = new_data_set ("tagged_run" )
142+ ds = new_data_set ("tagged_run" , exp_id = exp . exp_id , conn = db_conn )
137143 ds .set_interdependencies (interdeps )
138144 ds .mark_started ()
139145 ds .add_results ([{p_x .name : 1.0 , p_y .name : 2.0 }])
140146 ds .mark_completed ()
141147 ds .add_metadata ("my_tag" , "hello" )
142- ds .conn .close ()
143148
144149 # An existing ad-hoc metadata column is returned ...
145- overview = get_db_overview (db_path , extra_columns = ["my_tag" ])
150+ overview = get_db_overview (conn = db_conn , extra_columns = ["my_tag" ])
146151 assert overview [1 ]["my_tag" ] == "hello" # type: ignore[typeddict-item]
147152
148153 # ... while a non-existent column is silently skipped.
149- overview = get_db_overview (db_path , extra_columns = ["does_not_exist" ])
154+ overview = get_db_overview (conn = db_conn , extra_columns = ["does_not_exist" ])
150155 assert "does_not_exist" not in overview [1 ]
151156
152157
153- def test_get_db_overview_accepts_connection (tmp_path : Path ) -> None :
154- db_path = str (tmp_path / "conn.db" )
155- _make_db_with_runs (db_path , n_runs = 1 )
158+ def test_get_db_overview_accepts_connection (db_conn : AtomicConnection ) -> None :
159+ _create_runs (db_conn , n_runs = 1 )
156160
157- conn = connect (db_path )
158- try :
159- overview = get_db_overview (conn = conn )
160- assert set (overview .keys ()) == {1 }
161- # the externally supplied connection must remain usable
162- assert conn .execute ("SELECT COUNT(*) FROM runs" ).fetchone ()[0 ] == 1
163- finally :
164- conn .close ()
161+ overview = get_db_overview (conn = db_conn )
162+ assert set (overview .keys ()) == {1 }
163+ # the externally supplied connection must remain usable
164+ assert db_conn .execute ("SELECT COUNT(*) FROM runs" ).fetchone ()[0 ] == 1
165165
166166
167- def test_get_db_overview_rejects_conn_and_path (tmp_path : Path ) -> None :
168- db_path = str (tmp_path / "both.db" )
169- _make_db_with_runs (db_path , n_runs = 1 )
167+ def test_get_db_overview_rejects_conn_and_path (db_conn : AtomicConnection ) -> None :
168+ _create_runs (db_conn , n_runs = 1 )
170169
171- conn = connect (db_path )
172- try :
173- with pytest .raises (ValueError ):
174- get_db_overview (path_to_db = db_path , conn = conn )
175- finally :
176- conn .close ()
170+ with pytest .raises (ValueError ):
171+ get_db_overview (path_to_db = path_to_dbfile (db_conn ), conn = db_conn )
177172
178173
179- def test_get_db_overview_in_progress_uses_live_row_count (tmp_path : Path ) -> None :
180- db_path = str ( tmp_path / "in_progress.db" )
181- initialise_or_create_database_at ( db_path )
182- load_or_create_experiment ("exp" , sample_name = "sample" )
174+ def test_get_db_overview_in_progress_uses_live_row_count (
175+ db_conn : AtomicConnection ,
176+ ) -> None :
177+ exp = load_or_create_experiment ("exp" , sample_name = "sample" , conn = db_conn )
183178 p_x = ParamSpecBase ("x" , "numeric" )
184179 p_y = ParamSpecBase ("y" , "numeric" )
185180 interdeps = InterDependencies_ (dependencies = {p_y : (p_x ,)})
186181
187182 # run 1: started, still in progress, with 5 data points
188- ds_live = new_data_set ("live" )
183+ ds_live = new_data_set ("live" , exp_id = exp . exp_id , conn = db_conn )
189184 ds_live .set_interdependencies (interdeps )
190185 ds_live .mark_started ()
191186 for i in range (5 ):
192187 ds_live .add_results ([{p_x .name : float (i ), p_y .name : float (i )}])
193188 # run 2: started, in progress, no data yet
194- ds_empty = new_data_set ("empty" )
189+ ds_empty = new_data_set ("empty" , exp_id = exp . exp_id , conn = db_conn )
195190 ds_empty .set_interdependencies (interdeps )
196191 ds_empty .mark_started ()
197- ds_empty .conn .close () # shared connection for both datasets
198192
199- overview = get_db_overview (db_path )
193+ overview = get_db_overview (conn = db_conn )
200194
201195 # in-progress runs report the live results-table row count and have no
202196 # completed timestamp
@@ -207,37 +201,29 @@ def test_get_db_overview_in_progress_uses_live_row_count(tmp_path: Path) -> None
207201
208202
209203def test_get_db_overview_missing_results_table_reports_zero (
210- tmp_path : Path ,
204+ db_conn : AtomicConnection ,
211205) -> None :
212- db_path = str (tmp_path / "no_table.db" )
213- _make_db_with_runs (db_path , n_runs = 1 , n_points = 5 )
206+ _create_runs (db_conn , n_runs = 1 , n_points = 5 )
214207
215- conn = connect (db_path )
216- try :
217- (table_name ,) = conn .execute (
218- "SELECT result_table_name FROM runs WHERE run_id=1"
219- ).fetchone ()
220- conn .execute (f'DROP TABLE "{ table_name } "' )
221- conn .commit ()
222- finally :
223- conn .close ()
208+ (table_name ,) = db_conn .execute (
209+ "SELECT result_table_name FROM runs WHERE run_id=1"
210+ ).fetchone ()
211+ db_conn .execute (f'DROP TABLE "{ table_name } "' )
212+ db_conn .commit ()
224213
225214 # with the results table gone (and no shape info) the count is unknown;
226215 # ``result_counter`` is the run ordinal, not a data-point count, so it must
227216 # not be used as a fallback
228- overview = get_db_overview (db_path )
217+ overview = get_db_overview (conn = db_conn )
229218 assert overview [1 ]["records" ] == 0
230219
231220
232- def test_get_db_overview_query_error_returns_empty (tmp_path : Path ) -> None :
233- db_path = str (tmp_path / "broken.db" )
234- _make_db_with_runs (db_path , n_runs = 1 )
221+ def test_get_db_overview_query_error_returns_empty (
222+ db_conn : AtomicConnection ,
223+ ) -> None :
224+ _create_runs (db_conn , n_runs = 1 )
235225
236- conn = connect (db_path )
237- try :
238- # remove a table the overview query depends on so the JOIN fails
239- conn .execute ("DROP TABLE experiments" )
240- conn .commit ()
241- assert get_db_overview (conn = conn ) == {}
242- finally :
243- conn .close ()
226+ # remove a table the overview query depends on so the JOIN fails
227+ db_conn .execute ("DROP TABLE experiments" )
228+ db_conn .commit ()
229+ assert get_db_overview (conn = db_conn ) == {}
0 commit comments