Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change QuantumCircuit.metadata to always be a dict #9849

Merged
merged 12 commits into from
Apr 18, 2023
19 changes: 13 additions & 6 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import multiprocessing as mp
import string
import re
import warnings
import typing
from collections import OrderedDict, defaultdict, namedtuple
from typing import (
Expand Down Expand Up @@ -300,9 +301,7 @@ def __init__(

self.duration = None
self.unit = "dt"
if not isinstance(metadata, dict) and metadata is not None:
raise TypeError("Only a dictionary or None is accepted for circuit metadata")
self._metadata = metadata
self.metadata = {} if metadata is None else metadata

@staticmethod
def from_instructions(
Expand Down Expand Up @@ -469,7 +468,7 @@ def has_calibration_for(self, instr_context: tuple):

@property
def metadata(self) -> dict:
"""The user provided metadata associated with the circuit
"""The user provided metadata associated with the circuit.

The metadata for the circuit is a user provided ``dict`` of metadata
for the circuit. It will not be used to influence the execution or
Expand All @@ -483,8 +482,16 @@ def metadata(self) -> dict:
@metadata.setter
def metadata(self, metadata: dict | None):
"""Update the circuit metadata"""
if not isinstance(metadata, dict) and metadata is not None:
raise TypeError("Only a dictionary or None is accepted for circuit metadata")
if metadata is None:
metadata = {}
warnings.warn(
"Setting metadata to None was deprecated in Terra 0.24.0 and this ability will be "
"removed in a future release. Instead, set metadata to an empty dictionary.",
DeprecationWarning,
stacklevel=2,
)
elif not isinstance(metadata, dict):
raise TypeError("Only a dictionary is accepted for circuit metadata")
self._metadata = metadata

def __str__(self) -> str:
Expand Down
2 changes: 1 addition & 1 deletion qiskit/dagcircuit/dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def __init__(self):
self.name = None

# Circuit metadata
self.metadata = None
self.metadata = {}

# Set of wires (Register,idx) in the dag
self._wires = set()
Expand Down
2 changes: 1 addition & 1 deletion qiskit/dagcircuit/dagdependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def __init__(self):
self.name = None

# Circuit metadata
self.metadata = None
self.metadata = {}

# Directed multigraph whose nodes are operations(gates) and edges
# represent non-commutativity between two gates.
Expand Down
7 changes: 7 additions & 0 deletions qiskit/test/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@ def setUpClass(cls):
]
for msg in allow_DeprecationWarning_message:
warnings.filterwarnings("default", category=DeprecationWarning, message=msg)
# This warning should be fixed once Qiskit/qiskit-aer#1761 is in a release version of Aer.
warnings.filterwarnings(
"default",
category=DeprecationWarning,
module="qiskit_aer.*",
message="Setting metadata to None.*",
)


class FullQiskitTestCase(QiskitTestCase):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
upgrade:
- |
The :class:`.QuantumCircuit` :attr:`.QuantumCircuit.metadata` attribute now
always returns a dictionary, and can only be set to a dictionary. Previously,
its default value was ``None``, and could be manually set to ``None`` or a
dictionary.
- |
The default value of ``metadata`` in both :class:`.DAGCircuit` and
:class:`.DAGDependency` has been changed from ``None`` to ``{}`` for compatibility
with a similar attribute of :class:`.QuantumCircuit`.
deprecations:
- |
Setting the :class:`.QuantumCircuit` :attr:`.QuantumCircuit.metadata` attribute
to ``None`` has been deprecated. Instead, users should set it to an empty
dictionary if they want it to contain no data.
19 changes: 19 additions & 0 deletions test/python/circuit/test_circuit_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,25 @@ def test_metadata_copy_does_not_share_state(self):

self.assertEqual(qc1.metadata["a"], 0)

def test_metadata_is_dict(self):
"""Verify setting metadata to None in the constructor results in an empty dict."""
qc = QuantumCircuit(1)
metadata1 = qc.metadata
self.assertEqual(metadata1, {})

def test_metadata_raises(self):
"""Test that we must set metadata to a dict."""
qc = QuantumCircuit(1)
with self.assertRaises(TypeError):
qc.metadata = 1
ihincks marked this conversation as resolved.
Show resolved Hide resolved

def test_metdata_deprectation(self):
"""Test that setting metadata to None emits a deprecation warning."""
qc = QuantumCircuit(1)
with self.assertWarns(DeprecationWarning):
qc.metadata = None
self.assertEqual(qc.metadata, {})

def test_scheduling(self):
"""Test cannot return schedule information without scheduling."""
qc = QuantumCircuit(2)
Expand Down
6 changes: 6 additions & 0 deletions test/python/dagcircuit/test_dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,12 @@ def test_circuit_factors(self):
"""Test number of separable factors in circuit."""
self.assertEqual(self.dag.num_tensor_factors(), 2)

def test_default_metadata_value(self):
"""Test that the default DAGCircuit metadata is valid QuantumCircuit metadata."""
qc = QuantumCircuit(1)
qc.metadata = self.dag.metadata
self.assertEqual(qc.metadata, {})


class TestCircuitControlFlowProperties(QiskitTestCase):
"""Properties tests of DAGCircuit with control-flow instructions."""
Expand Down
6 changes: 6 additions & 0 deletions test/python/dagcircuit/test_dagdependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ def test_dag_depth_empty(self):
dag = circuit_to_dagdependency(qc)
self.assertEqual(dag.depth(), 0)

def test_default_metadata_value(self):
"""Test that the default DAGDependency metadata is valid QuantumCircuit metadata."""
qc = QuantumCircuit(1)
qc.metadata = self.dag.metadata
self.assertEqual(qc.metadata, {})


if __name__ == "__main__":
unittest.main()