QCoDeS [UNRELEASED DRAFT] (2026-09-28)¶
Breaking Changes:¶
Remove the deprecated TypeVars and type aliases that were retained as runtime compatibility imports after the conversion to PEP 695 type parameter syntax. Imports of
typing.TypeVarandtyping.ParamSpecare now banned: use PEP 695 type parameter syntax unless a default value requires the correspondingtyping_extensionstype on Python 3.12. (#8543)
Improved:¶
The documentation on naming instrument drivers (in the Contributor guide and in the “Creating Instrument Drivers” example notebook) has been updated to state that instrument driver modules should be named using lower case
snake_case, e.g.weinschel_8320.py. Vendor and model capitalization belongs in the class name (Weinschel8320) and not in the module name. (#8356)Exceptions raised by QCoDeS drivers are now more specific.
The ruff rule
TRY002(raise-vanilla-class) has been enabled. A number of drivers raised a bareException; these now raise a specific builtin exception instead. Invalid arguments raiseValueError, using the instrument in an unsupported state raisesRuntimeErrorand selecting an unimplemented acquisition mode on the AlazarTech ATS raisesNotImplementedError. Code that catchesExceptionis unaffected since all of these are subclasses ofException.In addition, two catch-all exception handlers have been narrowed to the specific exceptions that the guarded code can actually raise: reading a screenshot from the Keysight Infiniium now only handles
OSErrorandVisaIOError, and waiting for the Tektronix AWG5014 to become ready only handlesVisaIOError. Both previously swallowed unrelated errors.Finally, the coding style section of the contributor documentation now points at
ruff checkandruff format, configured inpyproject.toml, rather than the long removedpycodestyleandflake8based workflow. (#8368)Adding metadata that SQLite cannot store in a column now fails with a message naming the tag and its type.
A nested dict or a sequence previously surfaced as
sqlite3.ProgrammingError: Error binding parameter 1: type 'list' is not supported, which said nothing about which tag was at fault.validate_dynamic_column_datanow rejects such values with aTypeErrorsuggesting serialization, alongside its existing checks for invalid tags andNone. Values that NumPy registers a SQLite adapter for, such as scalars and arrays, are unaffected. (#8518)
Improved Drivers:¶
The Infiniium driver now tests explicitly for the type of parent instrument when required and used
castwherepyvisatypes the return ofread_binary_values/query_binary_valuesas aSequence[float]regardless of the requestedcontainer. This replaces five type checker suppressions. (#8457)
New:¶
Added split raw data storage for the DataSet: an opt-in results backend selected via the
dataset.raw_data_backendconfig option (set it to"sqlite_per_dataset_db") that writes raw measurement data into individual per-dataset SQLite files while keeping all metadata in the main database. This prevents the main DB file from growing excessively large and allows users to have a single main SQLite QCoDeS database on their PC as opposed to many that grow infinitely. When selected, no results table is created in the main database at all - it holds only metadata - and all publicDataSetAPIs continue to work unchanged. Backend-specific settings (such as the per-dataset file folderraw_data_path) live underdataset.raw_data_backend_config.Management helpers included:
update_raw_data_paths(): update stored paths after raw data files have been moved to a new folder.purge_orphaned_datasets(): find and remove dataset records whose raw data files no longer exist on disk (dry_run=Trueby default).cleanup_datasets(): remove datasets (DB records and raw data files) by age, sample name, or file size (dry_run=Trueby default). (#8219)
The method for setting a parameter’s cache from a raw value as reported by the instrument is now public as
Parameter.cache.set_from_raw_value. It is the raw-side counterpart ofParameter.cache.setand applies the same conversions as aget(get_parser,scale,offsetandval_mapping). This is useful for drivers that populate the caches of many parameters from a single bulk instrument reply without issuing agetper parameter. The previous private_set_from_raw_valueis kept as a backwards-compatible alias. (#8484)
Under the hood:¶
Enable the ruff rule
N999(invalid-module-name). Instrument driver modules that are part of the publicqcodesnamespace are exempted vialint.pep8-naming.extend-ignore-namesinpyproject.tomlso that no public module names change. Test modules with invalid names have been renamed to lower case. (#8356)CombinedParameter.parameteris now a small dataclass holding thename,full_name,labelandunitof the combined parameter, replacing a lambda that had those attributes attached to it. It remains callable, and calling it returnsNoneas before. (#8364)Two additional ruff lint rules have been enabled.
TRY004(type-check-without-type-error) ensures that new code raisesTypeErrorwhen rejecting a value because of its type. Existing type checks that raiseValueErrororRuntimeErrorare unchanged and carry an explicitnoqacomment, sinceTypeErroris not a subclass of either and changing them would break user code that catches the current exception.S110(try-except-pass) flags exception handlers that silently pass. No behaviour changed as a result: the only remaining silent handlers are in teardown paths that must never raise or log, and they are now explicitly marked as intentional. (#8368)Enable the ruff rule
BLE001(blind-except). Places where QCoDeS intentionally catches a broad exception are now explicitly marked, and several catch-all handlers now log the full traceback usingLogger.exceptionrather than only the exception message. The private module level loggers named_LOGhave been renamed to_LOGGER. (#8498)