Repository: PyPSA/PyPSA

Issue:
Cannot set network copy to None from an optimized network
### Version Checks (indicate both or one)

- [x] I have confirmed this bug exists on the lastest [release](https://github.com/pypsa/pypsa/releases) of PyPSA.

- [x] I have confirmed this bug exists on the current [`master`](https://github.com/pypsa/pypsa/tree/master) branch of PyPSA.


### Issue Description

Related to #1265 fix, the ValueError print generated specifies we can set the solver_model to None if want to copy the network (# ValueError: Copying a solved network with an attached solver model is not supported. Please delete the model first using `n.model.solver_model = None`). Trying it out, throws an errors.

### Reproducible Example

```python
import pypsa

network = pypsa.examples.ac_dc_meshed(from_master=True)
m = network.optimize()
# ValueError: Copying a solved network with an attached solver model is not supported. 
# Please delete the model first using `n.model.solver_model = None`.
network.model.solver_model = None
n_copy = network.copy()
```

### Expected Behavior

I would expect being able to reset the optimized linopy model and being able to copy the network.

### Installed Versions

<details>
python==3.12.9
pypsa==0.35.1
</details>

setting solver_model to none does not resolve non-copyable network
### Version Checks (indicate both or one)

- [x] I have confirmed this bug exists on the lastest [release](https://github.com/pypsa/pypsa/releases) of PyPSA.

- [x] I have confirmed this bug exists on the current [`master`](https://github.com/pypsa/pypsa/tree/master) branch of PyPSA.


### Issue Description

Copying a solved network where the `solver_model`  attribute of the underlying linopy model at `n.model` is set, will lead to the following error:

```python
E           ValueError: Copying a solved network with an attached solver model is not supported. Please delete the model first using `n.model.solver_model = None`.
```

when following this and setting the solver_model to None, the error is still raised. The reason is that the check is actually using `hasattr`

```python
        if self.is_solved and hasattr(self.model, "solver_model"):
```

### Reproducible Example

```python
import pypsa

n = pypsa.examples.ac_dc_meshed()

n.optimize()

n.model.solver_model = None

n.copy()
```

### Expected Behavior

the raised message should provide a valid solution

### Installed Versions

<details>
Replace this line.
</details>



Discussion:
Thanks for raising @BuiMCanmet !





Patch:
diff --git a/doc/references/release-notes.rst b/doc/references/release-notes.rst
index 563aac461..e7bc12a14 100644
--- a/doc/references/release-notes.rst
+++ b/doc/references/release-notes.rst
@@ -28,6 +28,9 @@ Features
 Bug Fixes
 ---------
 
+* Fixed issue when copying a solved network after setting ``solver_model`` to ``None``.
+  (https://github.com/PyPSA/PyPSA/issues/1325)
+
 * Correct use of snapshot weighting columns in statistics module. The
   doscstring for ``n.snapshot_weightings`` was clarified.
 
diff --git a/pypsa/networks.py b/pypsa/networks.py
index a7c0d5d06..6d54ad3a5 100644
--- a/pypsa/networks.py
+++ b/pypsa/networks.py
@@ -695,7 +695,12 @@ def copy(
         DatetimeIndex(['2015-01-01'], dtype='datetime64[ns]', name='snapshot', freq=None)
 
         """
-        if self.is_solved and hasattr(self._model, "solver_model"):
+        if (
+            self.is_solved
+            and hasattr(self._model, "solver_model")
+            and self._model is not None
+            and self._model.solver_model is not None
+        ):
             msg = "Copying a solved network with an attached solver model is not supported."
             msg += " Please delete the model first using `n.model.solver_model = None`."
             raise ValueError(msg)


Test patch:
diff --git a/test/test_bugs.py b/test/test_bugs.py
index e20793845..532332bb8 100644
--- a/test/test_bugs.py
+++ b/test/test_bugs.py
@@ -162,3 +162,24 @@ def test_1268(tmpdir):
     n = pypsa.Network()
     n.import_from_excel(fn)
     assert len(n.buses) == 1
+
+
+def test_1319():
+    """
+    Copying a solved network should work after setting solver_model to None.
+    See https://github.com/PyPSA/PyPSA/issues/1319.
+    """
+    n = pypsa.examples.ac_dc_meshed()
+    n.optimize()
+
+    # Should raise error when trying to copy with solver_model attached
+    with pytest.raises(
+        ValueError, match="Copying a solved network with an attached solver model"
+    ):
+        n.copy()
+
+    # Should work after setting solver_model to None
+    n.model.solver_model = None
+    n_copy = n.copy()  # Should not raise an error
+    assert n_copy is not n
+    assert len(n_copy.buses) == len(n.buses)