Repository: Qiskit/qiskit-terra (python)

Issue:
Drawing a circuit with idle_wires=False causes the circuit to break in future draw/qpy events
### Environment

- **Qiskit Terra version**: main
- **Python version**: 3.9.1
- **Operating system**: OSX


### What is happening?

When drawing a circuit with `circuit.draw(idle_wires=False)` the circuit is somehow mutated to fail on future drawing or qpy serialization events.



### How can we reproduce the issue?

Using the circuit below. Message for QPY file.

```python
from qiskit import qpy

with open('test.qpy', 'wb') as fd:
    qpy.dump(transpiled_bit_code_circuit, fd)

with open('test.qpy', 'rb') as fd:
    new_qc = qpy.load(fd)[0]
    
new_qc.draw(idle_wires=False)
new_qc.draw(idle_wires=False)
```



### What should happen?

Circuit should draw twice.

### Any suggestions?

_No response_

Pull request:
Fix circuit drawers mutating input circuits
### Summary

The wire management in the circuit drawers could accidentally mutate the qubits in the input circuit.  The root cause of this is because `QuantumCircuit.qubits` (and `.clbits`) are properties that expose the internal, mutable lists that back them directly.  This is a larger failing of the `QuantumCircuit` API, but one that is slightly tricky to walk back without backwards-incompatible changes or performance regressions.

<!--
⚠️ 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.
-->

### Details and comments

Fix #8739.  No release note because this regression was introduced by #8173, which hasn't been released yet.


Patch:
diff --git a/qiskit/visualization/circuit/_utils.py b/qiskit/visualization/circuit/_utils.py
index 26f2fb54d..63dc01caa 100644
--- a/qiskit/visualization/circuit/_utils.py
+++ b/qiskit/visualization/circuit/_utils.py
@@ -399,8 +399,8 @@ def _get_layered_instructions(
     # default to left
     justify = justify if justify in ("right", "none") else "left"
 
-    qubits = circuit.qubits
-    clbits = circuit.clbits
+    qubits = circuit.qubits.copy()
+    clbits = circuit.clbits.copy()
     nodes = []
 
     # Create a mapping of each register to the max layer number for all measure ops


Test patch:
diff --git a/test/python/visualization/test_circuit_text_drawer.py b/test/python/visualization/test_circuit_text_drawer.py
index fdd98a1f4..d570341f4 100644
--- a/test/python/visualization/test_circuit_text_drawer.py
+++ b/test/python/visualization/test_circuit_text_drawer.py
@@ -3447,6 +3447,13 @@ class TestTextIdleWires(QiskitTestCase):
         circuit.delay(100, qr[2])
         self.assertEqual(str(_text_circuit_drawer(circuit, idle_wires=False)), expected)
 
+    def test_does_not_mutate_circuit(self):
+        """Using 'idle_wires=False' should not mutate the circuit.  Regression test of gh-8739."""
+        circuit = QuantumCircuit(1)
+        before_qubits = circuit.num_qubits
+        circuit.draw(idle_wires=False)
+        self.assertEqual(circuit.num_qubits, before_qubits)
+
 
 class TestTextNonRational(QiskitTestCase):
     """non-rational numbers are correctly represented"""