Repository: PrefectHQ/prefect
Pull request: Support flow deletion in Prefect Python client
Closes #16307 in Prefect 3

Problem statement:
Prefect Python client does not support flow deletion
### Bug summary

The Prefect REST API supports flow removal via `DELETE` HTTP method on the `/api/flows/{flow_id}` endpoint. However, the Python Prefect client lacks this functionality, making it impossible to remove the flow without patching the client or calling the Prefect REST API directly.

### Version info

```Text
Version:             3.1.6.dev7+0.g8fd92fe5e6.dirty
API version:         0.8.4
Python version:      3.11.11
Git commit:          8fd92fe5
Built:               Sun, Dec 8, 2024 8:00 PM
OS/Arch:             darwin/arm64
Profile:             default
Server type:         server
Pydantic version:    2.10.3
```


### Additional context

The missing functionality affects both Prefect 2 and 3.

Hints from issue discussion:

Commit message: Merge branch 'main' into feature/deleting-flows-in-python-client

Patch to review:
diff --git a/src/prefect/client/orchestration.py b/src/prefect/client/orchestration.py
index bfcc6232192a..cb5e52dda782 100644
--- a/src/prefect/client/orchestration.py
+++ b/src/prefect/client/orchestration.py
@@ -501,6 +501,24 @@ async def read_flow(self, flow_id: UUID) -> Flow:
         response = await self._client.get(f"/flows/{flow_id}")
         return Flow.model_validate(response.json())
 
+    async def delete_flow(self, flow_id: UUID) -> None:
+        """
+        Delete a flow by UUID.
+
+        Args:
+            flow_id: ID of the flow to be deleted
+        Raises:
+            prefect.exceptions.ObjectNotFound: If request returns 404
+            httpx.RequestError: If requests fails
+        """
+        try:
+            await self._client.delete(f"/flows/{flow_id}")
+        except httpx.HTTPStatusError as e:
+            if e.response.status_code == status.HTTP_404_NOT_FOUND:
+                raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
+            else:
+                raise
+
     async def read_flows(
         self,
         *,
diff --git a/tests/client/test_prefect_client.py b/tests/client/test_prefect_client.py
index 6791adc95855..92f0f43f96cc 100644
--- a/tests/client/test_prefect_client.py
+++ b/tests/client/test_prefect_client.py
@@ -631,6 +631,19 @@ def foo():
     assert lookup.name == foo.name
 
 
+async def test_create_then_delete_flow(prefect_client):
+    @flow
+    def foo():
+        pass
+
+    flow_id = await prefect_client.create_flow(foo)
+    assert isinstance(flow_id, UUID)
+
+    await prefect_client.delete_flow(flow_id)
+    with pytest.raises(prefect.exceptions.PrefectHTTPStatusError, match="404"):
+        await prefect_client.read_flow(flow_id)
+
+
 async def test_create_then_read_deployment(prefect_client, storage_document_id):
     @flow
     def foo():


Code review comments:
diff_hunk: @@ -501,6 +501,24 @@ async def read_flow(self, flow_id: UUID) -> Flow:
         response = await self._client.get(f"/flows/{flow_id}")
         return Flow.model_validate(response.json())
 
+    async def delete_flow(self, flow_id: UUID) -> None:
+        """
+        Delete a flow by UUID.
+
+        Args:
+            flow_id: ID of the flow to be deleted
+        Raises:
+            prefect.exceptions.ObjectNotFound: If request returns 404
+            httpx.RequestError: If requests fails
path: src/prefect/client/orchestration.py
text: @user1:
```suggestion
            httpx.RequestError: If requests fail
```