Repository: Qiskit/qiskit-terra (python)

Issue:
Transpiling fails if the target does not specify properties for measurement instructions
### Environment

- **Qiskit Terra version**: 0.22.0
- **Python version**: 3.9.12
- **Operating system**: Windows 10


### What is happening?

```
Traceback (most recent call last):
  File ".\src\playground.py", line 86, in <module>
    qc_transpiled = transpile(qc, target=target)
  File ".\lib\site-packages\qiskit\compiler\transpiler.py", line 327, in transpile
    unique_transpile_args, shared_args = _parse_transpile_args(
  File ".\lib\site-packages\qiskit\compiler\transpiler.py", line 646, in _parse_transpile_args
    backend_properties = target_to_backend_properties(target)
  File ".\lib\site-packages\qiskit\transpiler\target.py", line 1021, in target_to_backend_properties
    if props.error is not None:
AttributeError: 'NoneType' object has no attribute 'error'
```

### How can we reproduce the issue?

When building a transpiler target, the properties for added instructions are optional. The documentation of `qiskit.transpiler.Target.add_instruction` says `Properties are optional for any instruction implementation, if there are no InstructionProperties available for the backend the value can be None.`. However, it seems this claim is true for all instructions except measurement. 

The below code snippet shows how to construct a very simple target with one qubit and measurement instruction associated with it. The measurement instruction does not have any properties (i.e. it is specified as `None`). Then, this target is used to transpile a circuit, which results into the error pasted above
```
from qiskit import QuantumCircuit
from qiskit.circuit.library import Measure
from qiskit.compiler import transpile
from qiskit.transpiler import Target

target = Target()
target.add_instruction(Measure(), {(0,): None})

qc = QuantumCircuit(1, 1)
qc.measure(0, 0)

transpile(qc, target=target)
```

### What should happen?

The transpilation should not fail

### Any suggestions?

_No response_

Pull request:
Fix transpile() with a Target containing an ideal Measure
<!--
⚠️ If you do not respect this template, your pull request will be closed.
⚠️ Your pull request title should be short detailed and understandable for all.
⚠️ Also, please add a release note file using reno if the change needs to be
  documented in the release notes.
⚠️ If your pull request fixes an open issue, please link to the issue.

- [ ] I have added the tests to cover my changes.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the CONTRIBUTING document.
-->

### Summary

This commit fixes an oversight in the transpile() function when running with a Target (either directly or via a backend) that contains a Measurement operation that is ideal (either globally or locally) with no properties defined. This was not handled correctly in the function used to convert a Target to a BackendProperties payload for passes that are not yet target aware and this would cause an exception to be raised. This commit fixes this edge case and excludes readout properties from the generated BackendProperties in this case.

### Details and comments

Fixes #8969

Patch:
diff --git a/qiskit/transpiler/target.py b/qiskit/transpiler/target.py
index 769ad9fe5..0a1a57894 100644
--- a/qiskit/transpiler/target.py
+++ b/qiskit/transpiler/target.py
@@ -1043,24 +1043,25 @@ def target_to_backend_properties(target: Target):
                     continue
                 qubit = qargs[0]
                 props_list = []
-                if props.error is not None:
-                    props_list.append(
-                        {
-                            "date": datetime.datetime.utcnow(),
-                            "name": "readout_error",
-                            "unit": "",
-                            "value": props.error,
-                        }
-                    )
-                if props.duration is not None:
-                    props_list.append(
-                        {
-                            "date": datetime.datetime.utcnow(),
-                            "name": "readout_length",
-                            "unit": "s",
-                            "value": props.duration,
-                        }
-                    )
+                if props is not None:
+                    if props.error is not None:
+                        props_list.append(
+                            {
+                                "date": datetime.datetime.utcnow(),
+                                "name": "readout_error",
+                                "unit": "",
+                                "value": props.error,
+                            }
+                        )
+                    if props.duration is not None:
+                        props_list.append(
+                            {
+                                "date": datetime.datetime.utcnow(),
+                                "name": "readout_length",
+                                "unit": "s",
+                                "value": props.duration,
+                            }
+                        )
                 if not props_list:
                     qubit_props = {}
                     break
diff --git a/releasenotes/notes/fix-transpile-ideal-measurement-c37e04533e196ded.yaml b/releasenotes/notes/fix-transpile-ideal-measurement-c37e04533e196ded.yaml
new file mode 100644
index 000000000..a1a30dfaf
--- /dev/null
+++ b/releasenotes/notes/fix-transpile-ideal-measurement-c37e04533e196ded.yaml
@@ -0,0 +1,10 @@
+---
+fixes:
+  - |
+    Fixed an issue with :func:`~.transpile` when targeting a :class:`~.Target`
+    (either directly via the ``target`` argument or via a
+    :class:`~.BackendV2` instance from the ``backend`` argument) that
+    contained an ideal :class:`~.Measure` instruction (one that does not have
+    any properties defined). Previously this would raise an exception
+    trying to parse the target.
+    Fixed `#8969 <https://github.com/Qiskit/qiskit-terra/issues/8969>`__


Test patch:
diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py
index 63c3633ff..5d42c49b5 100644
--- a/test/python/compiler/test_transpiler.py
+++ b/test/python/compiler/test_transpiler.py
@@ -1726,6 +1726,19 @@ class TestPostTranspileIntegration(QiskitTestCase):
         # itself doesn't throw an error, though.
         self.assertIsInstance(qasm3.dumps(transpiled).strip(), str)
 
+    @data(0, 1, 2, 3)
+    def test_transpile_target_no_measurement_error(self, opt_level):
+        """Test that transpile with a target which contains ideal measurement works
+
+        Reproduce from https://github.com/Qiskit/qiskit-terra/issues/8969
+        """
+        target = Target()
+        target.add_instruction(Measure(), {(0,): None})
+        qc = QuantumCircuit(1, 1)
+        qc.measure(0, 0)
+        res = transpile(qc, target=target, optimization_level=opt_level)
+        self.assertEqual(qc, res)
+
 
 class StreamHandlerRaiseException(StreamHandler):
     """Handler class that will raise an exception on formatting errors."""