From 72f09adf7e434dbdfc84b6a2cf12af044f99cf8d Mon Sep 17 00:00:00 2001 From: Will Shanks Date: Thu, 6 Jun 2024 19:29:08 -0400 Subject: [PATCH] Avoid exception in `Target.has_calibration` for instruction without properties (#12526) `Target.add_instruction` allows passing `None` in place of an `InstructionProperties` instance. In this case, there will be no `_calibration` attribute, so the `getattr` call properties needs to provide a default value. --- qiskit/transpiler/target.py | 2 +- ...ration-no-properties-f3be18f2d58f330a.yaml | 7 ++++++ test/python/transpiler/test_target.py | 25 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/target-has-calibration-no-properties-f3be18f2d58f330a.yaml diff --git a/qiskit/transpiler/target.py b/qiskit/transpiler/target.py index f7b5227c0266..53daa4ccbe65 100644 --- a/qiskit/transpiler/target.py +++ b/qiskit/transpiler/target.py @@ -892,7 +892,7 @@ def has_calibration( return False if qargs not in self._gate_map[operation_name]: return False - return getattr(self._gate_map[operation_name][qargs], "_calibration") is not None + return getattr(self._gate_map[operation_name][qargs], "_calibration", None) is not None def get_calibration( self, diff --git a/releasenotes/notes/target-has-calibration-no-properties-f3be18f2d58f330a.yaml b/releasenotes/notes/target-has-calibration-no-properties-f3be18f2d58f330a.yaml new file mode 100644 index 000000000000..07970679722d --- /dev/null +++ b/releasenotes/notes/target-has-calibration-no-properties-f3be18f2d58f330a.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + :meth:`.Target.has_calibration` has been updated so that it does not raise + an exception for an instruction that has been added to the target with + ``None`` for its instruction properties. Fixes + `#12525 `__. diff --git a/test/python/transpiler/test_target.py b/test/python/transpiler/test_target.py index 646b29dd3832..f63ed5061cc7 100644 --- a/test/python/transpiler/test_target.py +++ b/test/python/transpiler/test_target.py @@ -1366,6 +1366,31 @@ def test_get_empty_target_calibration(self): self.assertIsNone(target["x"][(0,)].calibration) + def test_has_calibration(self): + target = Target() + properties = { + (0,): InstructionProperties(duration=100, error=0.1), + (1,): None, + } + target.add_instruction(XGate(), properties) + + # Test false for properties with no calibration + self.assertFalse(target.has_calibration("x", (0,))) + # Test false for no properties + self.assertFalse(target.has_calibration("x", (1,))) + + properties = { + (0,): InstructionProperties( + duration=self.custom_sx_q0.duration, + error=None, + calibration=self.custom_sx_q0, + ) + } + target.add_instruction(SXGate(), properties) + + # Test true for properties with calibration + self.assertTrue(target.has_calibration("sx", (0,))) + def test_loading_legacy_ugate_instmap(self): # This is typical IBM backend situation. # IBM provider used to have u1, u2, u3 in the basis gates and