Adding metadata dict more than one level deep creates invalid run
- Dominant language
- Python
- Stars
- 459
- Forks
- 359
- Avg merge
- 3d 6h
- Merged PRs (30d)
- 73
Description
```python
import qcodes as qc
from qcodes import ParamSpec, new_data_set, new_experiment
dataSet = new_data_set("sweep gate")
exp = new_experiment("majorana-qbuit", sample_name="flying brdige")
parameter_a = ParamSpec("a", "numeric")
parameter_b = ParamSpec("b", "numeric", key="value", number=1)
parameter_c = ParamSpec("c", "array")
dataSet = new_data_set("sweep gate", specs=[parameter_a,parameter_b,parameter_c], metadata={'a': {'b': 1}})
```
results in
```
Rolling back due to unhandled exception
Traceback (most recent call last):
File "c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py", line 819, in atomic
yield conn
File "c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py", line 781, in atomic_transaction
c = transaction(atomic_conn, sql, *args)
File "c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py", line 756, in transaction
c.execute(sql, args)
sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type.
---------------------------------------------------------------------------
InterfaceError Traceback (most recent call last)
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in atomic(conn)
818 conn.cursor().execute('BEGIN')
--> 819 yield conn
820 except Exception as e:
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in atomic_transaction(conn, sql, *args)
780 with atomic(conn) as atomic_conn:
--> 781 c = transaction(atomic_conn, sql, *args)
782 return c
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in transaction(conn, sql, *args)
755 if len(args) > 0:
--> 756 c.execute(sql, args)
757 else:
InterfaceError: Error binding parameter 0 - probably unsupported type.
The above exception was the direct cause of the following exception:
RuntimeError Traceback (most recent call last)
in
----> 1 dataSet = new_data_set("sweep gate", specs=[parameter_a,parameter_b,parameter_c], metadata={'a': {'b': 1}})
2 exp
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\data_set.py in new_data_set(name, exp_id, specs, values, metadata, conn)
1080 d = DataSet(path_to_db=None, run_id=None, conn=conn,
1081 name=name, specs=specs, values=values,
-> 1082 metadata=metadata, exp_id=exp_id)
1083
1084 return d
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\data_set.py in __init__(self, path_to_db, run_id, conn, exp_id, name, specs, values, metadata)
268 _, run_id, __ = create_run(self.conn, exp_id, name,
269 generate_guid(),
--> 270 specs, values, metadata)
271 # this is really the UUID (an ever increasing count in the db)
272 self._run_id = run_id
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in create_run(conn, exp_id, name, guid, parameters, values, metadata)
2297 parameters)
2298 if metadata:
-> 2299 add_meta_data(conn, run_id, metadata)
2300 _update_experiment_run_counter(conn, exp_id, run_counter)
2301 _create_run_table(conn, formatted_name, parameters, values)
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in add_meta_data(conn, row_id, metadata, table_name)
2394 """
2395 try:
-> 2396 insert_meta_data(conn, row_id, table_name, metadata)
2397 except sqlite3.OperationalError as e:
2398 # this means that the column already exists
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in insert_meta_data(conn, row_id, table_name, metadata)
2362 for key in metadata.keys():
2363 insert_column(conn, table_name, key)
-> 2364 update_meta_data(conn, row_id, table_name, metadata)
2365
2366
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in update_meta_data(conn, row_id, table_name, metadata)
2376 - metadata: the metadata to add
2377 """
-> 2378 update_where(conn, table_name, 'rowid', row_id, **metadata)
2379
2380
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in update_where(conn, table, where_column, where_value, **updates)
989 {where_column} = ?
990 """
--> 991 atomic_transaction(conn, query, *values, where_value)
992
993
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in atomic_transaction(conn, sql, *args)
779 """
780 with atomic(conn) as atomic_conn:
--> 781 c = transaction(atomic_conn, sql, *args)
782 return c
783
~\AppData\Local\Continuum\miniconda3\envs\qcodes\lib\contextlib.py in __exit__(self, type, value, traceback)
97 value = type()
98 try:
---> 99 self.gen.throw(type, value, traceback)
100 except StopIteration as exc:
101 # Suppress StopIteration *unless* it's the same exception that
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in atomic(conn)
821 conn.rollback()
822 log.exception("Rolling back due to unhandled exception")
--> 823 raise RuntimeError("Rolling back due to unhandled exception") from e
824 else:
825 if is_outmost:
RuntimeError: Rolling back due to unhandled exception
```
Subsequent runs then fail even without the metadata because 2 rows with the same run_id are created
```
dataSet = new_data_set("sweep gate", specs=[parameter_a,parameter_b,parameter_c])
```
fails with:
```
Rolling back due to unhandled exception
Traceback (most recent call last):
File "c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py", line 819, in atomic
yield conn
File "c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py", line 1964, in _insert_run
*parameters)
File "c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py", line 2168, in _add_parameters_to_layout_and_deps
run_id = one(transaction(conn, sql), 'run_id')
File "c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py", line 285, in one
raise RuntimeError("Expected only one row")
RuntimeError: Expected only one row
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in atomic(conn)
818 conn.cursor().execute('BEGIN')
--> 819 yield conn
820 except Exception as e:
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in _insert_run(conn, exp_id, name, guid, parameters)
1963 _add_parameters_to_layout_and_deps(conn, formatted_name,
-> 1964 *parameters)
1965
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in _add_parameters_to_layout_and_deps(conn, formatted_name, *parameter)
2167 """
-> 2168 run_id = one(transaction(conn, sql), 'run_id')
2169 layout_args = []
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in one(curr, column)
284 if len(res) > 1:
--> 285 raise RuntimeError("Expected only one row")
286 elif len(res) == 0:
RuntimeError: Expected only one row
The above exception was the direct cause of the following exception:
RuntimeError Traceback (most recent call last)
in
----> 1 dataSet = new_data_set("sweep gate", specs=[parameter_a,parameter_b,parameter_c])
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\data_set.py in new_data_set(name, exp_id, specs, values, metadata, conn)
1080 d = DataSet(path_to_db=None, run_id=None, conn=conn,
1081 name=name, specs=specs, values=values,
-> 1082 metadata=metadata, exp_id=exp_id)
1083
1084 return d
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\data_set.py in __init__(self, path_to_db, run_id, conn, exp_id, name, specs, values, metadata)
268 _, run_id, __ = create_run(self.conn, exp_id, name,
269 generate_guid(),
--> 270 specs, values, metadata)
271 # this is really the UUID (an ever increasing count in the db)
272 self._run_id = run_id
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in create_run(conn, exp_id, name, guid, parameters, values, metadata)
2295 name,
2296 guid,
-> 2297 parameters)
2298 if metadata:
2299 add_meta_data(conn, run_id, metadata)
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in _insert_run(conn, exp_id, name, guid, parameters)
1986 time.time(),
1987 False,
-> 1988 desc_str)
1989 run_id = curr.lastrowid
1990 return run_counter, formatted_name, run_id
~\AppData\Local\Continuum\miniconda3\envs\qcodes\lib\contextlib.py in __exit__(self, type, value, traceback)
97 value = type()
98 try:
---> 99 self.gen.throw(type, value, traceback)
100 except StopIteration as exc:
101 # Suppress StopIteration *unless* it's the same exception that
c:\users\jenielse\source\repos\qcodes\qcodes\dataset\sqlite_base.py in atomic(conn)
821 conn.rollback()
822 log.exception("Rolling back due to unhandled exception")
--> 823 raise RuntimeError("Rolling back due to unhandled exception") from e
824 else:
825 if is_outmost:
RuntimeError: Rolling back due to unhandled exception
```
Contributor guide
Research direction
Start with the metadata path in qcodes/dataset/sqlite_base.py, especially add_meta_data, insert_meta_data, update_meta_data, and the atomic transaction helpers; review how data_set.py calls create_run. Run the nested-metadata reproduction, then repeat the subsequent new_data_set call. Done means nested metadata does not create an invalid run and later runs succeed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, sqlite
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100