Skip to content

Commit dfd03a7

Browse files
authored
Merge branch 'main' into trlemon/refactor-keithley2600-driver-fastsweep
2 parents 2e59164 + b0a7b55 commit dfd03a7

9 files changed

Lines changed: 284 additions & 50 deletions

File tree

.github/workflows/codeql-analysis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ jobs:
3939

4040
# Initializes the CodeQL tools for scanning.
4141
- name: Initialize CodeQL
42-
uses: github/codeql-action/init@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v3.29.5
42+
uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5
4343
with:
4444
languages: ${{ matrix.language }}
4545

4646
- name: Autobuild
47-
uses: github/codeql-action/autobuild@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v3.29.5
47+
uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5
4848

4949
- name: Perform CodeQL Analysis
50-
uses: github/codeql-action/analyze@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v3.29.5
50+
uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5

.github/workflows/scorecards.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,6 @@ jobs:
7171

7272
# Upload the results to GitHub's code scanning dashboard.
7373
- name: "Upload to code-scanning"
74-
uses: github/codeql-action/upload-sarif@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v3.29.5
74+
uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5
7575
with:
7676
sarif_file: results.sarif
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Fixed ``to_xarray_dataset`` failing with a ``MergeError`` when exporting
2+
incomplete measurements where a shared setpoint parameter was treated as a
3+
coordinate in some sub-datasets and a data variable in others. This could
4+
happen when the actual data shape did not match the declared shape (e.g. a
5+
measurement that was interrupted before completion) and one of the sweep axes
6+
had non-unique values, causing different export code paths to disagree on the
7+
role of the shared setpoint.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
``initialise_database``, ``initialise_or_create_database_at``, and ``initialised_database_at``
2+
now accept more consistent arguments:
3+
4+
- ``initialise_database`` accepts a new ``db_path`` parameter to specify the database file
5+
location directly, instead of always reading from the config.
6+
- ``initialised_database_at`` accepts a new ``journal_mode`` parameter, consistent with
7+
``initialise_database`` and ``initialise_or_create_database_at``.

requirements.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ jinja2==3.1.6
137137
# nbsphinx
138138
# sphinx
139139
# towncrier
140-
jsonpointer==3.0.0
140+
jsonpointer==3.1.1
141141
# via sphinx-jsonschema
142142
jsonref==1.1.0
143143
# via zhinst-toolkit
@@ -317,7 +317,7 @@ pytest==9.0.2
317317
# pytest-xdist
318318
pytest-asyncio==1.3.0
319319
# via qcodes (pyproject.toml)
320-
pytest-cov==7.0.0
320+
pytest-cov==7.1.0
321321
# via qcodes (pyproject.toml)
322322
pytest-mock==3.15.1
323323
# via qcodes (pyproject.toml)
@@ -454,13 +454,13 @@ traitlets==5.14.3
454454
# nbconvert
455455
# nbformat
456456
# nbsphinx
457-
types-jsonschema==4.26.0.20260202
457+
types-jsonschema==4.26.0.20260324
458458
# via qcodes (pyproject.toml)
459-
types-networkx==3.6.1.20260303
459+
types-networkx==3.6.1.20260321
460460
# via qcodes (pyproject.toml)
461-
types-pywin32==311.0.0.20260317
461+
types-pywin32==311.0.0.20260323
462462
# via qcodes (pyproject.toml)
463-
types-requests==2.32.4.20260107
463+
types-requests==2.32.4.20260324
464464
# via
465465
# qcodes (pyproject.toml)
466466
# types-tqdm

src/qcodes/dataset/exporters/export_to_xarray.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,25 @@ def load_to_xarray_dataset(
286286
dataset, data, use_multi_index=use_multi_index
287287
)
288288

289+
# When shapes are inconsistent (e.g. incomplete measurements), different
290+
# code paths may represent the same setpoint parameter as a coordinate in
291+
# some sub-datasets and a data variable in others. xr.merge refuses to
292+
# combine them when the role is ambiguous, so we normalise first by
293+
# promoting any such variable to a coordinate everywhere.
294+
all_coords: set[Hashable] = set()
295+
all_data_vars: set[Hashable] = set()
296+
for xr_ds in xr_dataset_dict.values():
297+
all_coords.update(xr_ds.coords)
298+
all_data_vars.update(xr_ds.data_vars)
299+
conflicting = all_coords & all_data_vars
300+
if conflicting:
301+
for key in xr_dataset_dict:
302+
vars_to_promote = [
303+
v for v in conflicting if v in xr_dataset_dict[key].data_vars
304+
]
305+
if vars_to_promote:
306+
xr_dataset_dict[key] = xr_dataset_dict[key].set_coords(vars_to_promote)
307+
289308
xr_dataset = xr.merge(xr_dataset_dict.values(), compat="equals", join="outer")
290309

291310
_add_param_spec_to_xarray_coords(dataset, xr_dataset)

src/qcodes/dataset/sqlite/database.py

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,10 @@ def get_DB_debug() -> bool:
220220
return bool(qcodes.config["core"]["db_debug"])
221221

222222

223-
def initialise_database(journal_mode: JournalMode | None = "WAL") -> None:
223+
def initialise_database(
224+
journal_mode: JournalMode | None = "WAL",
225+
db_path: str | Path | None = None,
226+
) -> None:
224227
"""
225228
Initialise a database in the location specified by the config object
226229
and set ``atomic commit and rollback mode`` of the db. The db is created
@@ -232,45 +235,28 @@ def initialise_database(journal_mode: JournalMode | None = "WAL") -> None:
232235
journal_mode: Which `journal_mode` should be used for atomic commit and rollback.
233236
Options are DELETE, TRUNCATE, PERSIST, MEMORY, WAL and OFF. If set to None
234237
no changes are made.
238+
db_path: Path to database file. If None, the path specified in the config object is used.
235239
236240
"""
237241
# calling connect performs all the needed actions to create and upgrade
238242
# the db to the latest version.
239-
conn = connect(get_DB_location(), get_DB_debug())
243+
if db_path is None:
244+
db_path = get_DB_location()
245+
conn = connect(db_path, get_DB_debug())
240246
reset_default_experiment_id(conn)
241247
if journal_mode is not None:
242248
set_journal_mode(conn, journal_mode)
243249
conn.close()
244250
del conn
245251

246252

247-
def set_journal_mode(conn: AtomicConnection, journal_mode: JournalMode) -> None:
248-
"""
249-
Set the ``atomic commit and rollback mode`` of the sqlite database.
250-
See https://www.sqlite.org/pragma.html#pragma_journal_mode for details.
251-
252-
Args:
253-
conn: Connection to the database.
254-
journal_mode: Which `journal_mode` should be used for atomic commit and rollback.
255-
Options are DELETE, TRUNCATE, PERSIST, MEMORY, WAL and OFF.
256-
257-
"""
258-
valid_journal_modes = ["DELETE", "TRUNCATE", "PERSIST", "MEMORY", "WAL", "OFF"]
259-
if journal_mode not in valid_journal_modes:
260-
raise RuntimeError(
261-
f"Invalid journal_mode {journal_mode} Valid modes are {valid_journal_modes}"
262-
)
263-
query = f"PRAGMA journal_mode={journal_mode};"
264-
cursor = conn.cursor()
265-
cursor.execute(query)
266-
267-
268253
def initialise_or_create_database_at(
269254
db_file_with_abs_path: str | Path, journal_mode: JournalMode | None = "WAL"
270255
) -> None:
271256
"""
272-
This function sets up QCoDeS to refer to the given database file. If the
273-
database file does not exist, it will be initiated.
257+
Initialises or creates a database at the specified location and configures QCoDeS to use
258+
this as the default database for the duration of the session.
259+
274260
275261
Args:
276262
db_file_with_abs_path: Database file name with absolute path, for example
@@ -285,23 +271,52 @@ def initialise_or_create_database_at(
285271

286272

287273
@contextmanager
288-
def initialised_database_at(db_file_with_abs_path: str | Path) -> Iterator[None]:
274+
def initialised_database_at(
275+
db_file_with_abs_path: str | Path, *, journal_mode: JournalMode | None = "WAL"
276+
) -> Iterator[None]:
289277
"""
290-
Initializes or creates a database and restores the 'db_location' afterwards.
278+
Initialises or creates a database at the specified location, configures QCoDeS to use this as the
279+
default database for the duration of the context, and restores the 'db_location' afterwards.
291280
292281
Args:
293282
db_file_with_abs_path: Database file name with absolute path, for example
294283
``C:\\mydata\\majorana_experiments.db``
284+
journal_mode: Which `journal_mode` should be used for atomic commit and rollback.
285+
Options are DELETE, TRUNCATE, PERSIST, MEMORY, WAL and OFF. If set to None
286+
no changes are made.
295287
296288
"""
297289
db_location = qcodes.config["core"]["db_location"]
298290
try:
299-
initialise_or_create_database_at(db_file_with_abs_path)
291+
initialise_or_create_database_at(
292+
db_file_with_abs_path, journal_mode=journal_mode
293+
)
300294
yield
301295
finally:
302296
qcodes.config["core"]["db_location"] = db_location
303297

304298

299+
def set_journal_mode(conn: AtomicConnection, journal_mode: JournalMode) -> None:
300+
"""
301+
Set the ``atomic commit and rollback mode`` of the sqlite database.
302+
See https://www.sqlite.org/pragma.html#pragma_journal_mode for details.
303+
304+
Args:
305+
conn: Connection to the database.
306+
journal_mode: Which `journal_mode` should be used for atomic commit and rollback.
307+
Options are DELETE, TRUNCATE, PERSIST, MEMORY, WAL and OFF.
308+
309+
"""
310+
valid_journal_modes = ["DELETE", "TRUNCATE", "PERSIST", "MEMORY", "WAL", "OFF"]
311+
if journal_mode not in valid_journal_modes:
312+
raise RuntimeError(
313+
f"Invalid journal_mode {journal_mode} Valid modes are {valid_journal_modes}"
314+
)
315+
query = f"PRAGMA journal_mode={journal_mode};"
316+
cursor = conn.cursor()
317+
cursor.execute(query)
318+
319+
305320
def conn_from_dbpath_or_conn(
306321
conn: AtomicConnection | None,
307322
path_to_db: str | Path | None,

0 commit comments

Comments
 (0)