Repository: Qiskit/qiskit (python)

Issue:
`Target.has_calibration` errors for instructions without properties
### Environment

- **Qiskit version**: 1.1.0
- **Python version**: 3.12
- **Operating system**: Fedora Linux 40


### What is happening?

If a `Target` has an `Instruction` with `None` for its `InstructionProperties`, `Target.has_calibration` raises an `AttributeError`.

### How can we reproduce the issue?

Consider this case from the `Target` docstring with the `has_calibration` call added at the end:

```python
from qiskit.circuit.library import CXGate
from qiskit.transpiler import Target, InstructionProperties

target = Target()
cx_properties = {
    (0, 1): None,
    (1, 0): None,
    (0, 2): None,
    (2, 0): None,
    (0, 3): None,
    (2, 3): None,
    (3, 0): None,
    (3, 2): None
}
target.add_instruction(CXGate(), cx_properties)

target.has_calibration("cx", (0, 1))  # AttributeError!
```

### What should happen?

The last line above should return `False`

### Any suggestions?

I will submit a PR.

Pull request description:
Avoid exception in `Target.has_calibration` for instruction without properties (backport #12526)




### Summary

Avoid exception in `Target.has_calibration` for instruction without properties

### Details and comments

`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, as done in this change.

Closes #12525 
<hr>This is an automatic backport of pull request #12526 done by [Mergify](https://mergify.com).

Patch:
diff --git a/qiskit/transpiler/target.py b/qiskit/transpiler/target.py
index 8d609ce3b..4b6f0d128 100644
--- a/qiskit/transpiler/target.py
+++ b/qiskit/transpiler/target.py
@@ -890,7 +890,7 @@ class Target(Mapping):
             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 000000000..079706797
--- /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 <https://github.com/Qiskit/qiskit/issues/12525>`__.


Test patch:
diff --git a/test/python/transpiler/test_target.py b/test/python/transpiler/test_target.py
index 646b29dd3..f63ed5061 100644
--- a/test/python/transpiler/test_target.py
+++ b/test/python/transpiler/test_target.py
@@ -1366,6 +1366,31 @@ Instructions:
 
         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