Repository: Qiskit/qiskit

Issue:
PassManagerConfig.from_backend fails with AerSimulator
### Environment

- **Qiskit Terra version**:  088f600be1914bfd2bc3c43d0a171ff08ccba9bf
- **Python version**: 3.10.8
- **Operating system**: Fedora 36
- **Qiskit Aer version**: 0.11.2


### What is happening?

See repro.

### How can we reproduce the issue?

```python
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit_aer import AerSimulator

backend = AerSimulator()
pass_manager_config = PassManagerConfig.from_backend(backend)
```
```
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In [1], line 5
      2 from qiskit_aer import AerSimulator
      4 backend = AerSimulator()
----> 5 pass_manager_config = PassManagerConfig.from_backend(backend)

File ~/projects/qiskit-terra/qiskit/transpiler/passmanager_config.py:139, in PassManagerConfig.from_backend(cls, backend, **pass_manager_options)
    137 if backend_version < 2:
    138     if hasattr(backend, "defaults"):
--> 139         res.inst_map = backend.defaults().instruction_schedule_map
    140 else:
    141     res.inst_map = backend.instruction_schedule_map

AttributeError: 'NoneType' object has no attribute 'instruction_schedule_map'
```

### What should happen?

It should work.

### Any suggestions?

_No response_


Discussion:

Resolving patch:
diff --git a/qiskit/transpiler/instruction_durations.py b/qiskit/transpiler/instruction_durations.py
--- a/qiskit/transpiler/instruction_durations.py
+++ b/qiskit/transpiler/instruction_durations.py
@@ -74,15 +74,17 @@ def from_backend(cls, backend: Backend):
         """
         # All durations in seconds in gate_length
         instruction_durations = []
-        for gate, insts in backend.properties()._gates.items():
-            for qubits, props in insts.items():
-                if "gate_length" in props:
-                    gate_length = props["gate_length"][0]  # Throw away datetime at index 1
-                    instruction_durations.append((gate, qubits, gate_length, "s"))
-        for q, props in backend.properties()._qubits.items():
-            if "readout_length" in props:
-                readout_length = props["readout_length"][0]  # Throw away datetime at index 1
-                instruction_durations.append(("measure", [q], readout_length, "s"))
+        backend_properties = backend.properties()
+        if hasattr(backend_properties, "_gates"):
+            for gate, insts in backend_properties._gates.items():
+                for qubits, props in insts.items():
+                    if "gate_length" in props:
+                        gate_length = props["gate_length"][0]  # Throw away datetime at index 1
+                        instruction_durations.append((gate, qubits, gate_length, "s"))
+            for q, props in backend.properties()._qubits.items():
+                if "readout_length" in props:
+                    readout_length = props["readout_length"][0]  # Throw away datetime at index 1
+                    instruction_durations.append(("measure", [q], readout_length, "s"))
 
         try:
             dt = backend.configuration().dt
diff --git a/qiskit/transpiler/passmanager_config.py b/qiskit/transpiler/passmanager_config.py
--- a/qiskit/transpiler/passmanager_config.py
+++ b/qiskit/transpiler/passmanager_config.py
@@ -136,7 +136,9 @@ def from_backend(cls, backend, **pass_manager_options):
         if res.inst_map is None:
             if backend_version < 2:
                 if hasattr(backend, "defaults"):
-                    res.inst_map = backend.defaults().instruction_schedule_map
+                    defaults = backend.defaults()
+                    if defaults is not None:
+                        res.inst_map = defaults.instruction_schedule_map
             else:
                 res.inst_map = backend.instruction_schedule_map
         if res.coupling_map is None:


Test patch:
diff --git a/test/python/transpiler/test_passmanager_config.py b/test/python/transpiler/test_passmanager_config.py
--- a/test/python/transpiler/test_passmanager_config.py
+++ b/test/python/transpiler/test_passmanager_config.py
@@ -16,6 +16,7 @@
 from qiskit.providers.backend import Backend
 from qiskit.test import QiskitTestCase
 from qiskit.providers.fake_provider import FakeMelbourne, FakeArmonk, FakeHanoi, FakeHanoiV2
+from qiskit.providers.basicaer import QasmSimulatorPy
 from qiskit.transpiler.coupling import CouplingMap
 from qiskit.transpiler.passmanager_config import PassManagerConfig
 
@@ -71,6 +72,21 @@ def test_from_backend_and_user(self):
         )
         self.assertEqual(config.initial_layout, initial_layout)
 
+    def test_from_backendv1_inst_map_is_none(self):
+        """Test that from_backend() works with backend that has defaults defined as None."""
+        backend = FakeHanoi()
+        backend.defaults = lambda: None
+        config = PassManagerConfig.from_backend(backend)
+        self.assertIsInstance(config, PassManagerConfig)
+        self.assertIsNone(config.inst_map)
+
+    def test_simulator_backend_v1(self):
+        """Test that from_backend() works with backendv1 simulator."""
+        backend = QasmSimulatorPy()
+        config = PassManagerConfig.from_backend(backend)
+        self.assertIsInstance(config, PassManagerConfig)
+        self.assertIsNone(config.inst_map)
+
     def test_invalid_user_option(self):
         """Test from_backend() with an invalid user option."""
         with self.assertRaises(TypeError):