Repository: PrefectHQ/prefect

Issue:
Ability to run_deployment by providing deployment id instead of deployment name
### First check

- [X] I added a descriptive title to this issue.
- [X] I used the GitHub search to find a similar request and didn't find it.
- [X] I searched the Prefect documentation for this feature.

### Prefect Version

2.x

### Describe the current behavior

Right now the [`run_deployment()`](https://orion-docs.prefect.io/api-ref/prefect/deployments/#prefect.deployments.run_deployment) function is really useful when we want to start a deployed flow run from the Python API. However it requires us to provide the deployment name in the in the form "/".

### Describe the proposed behavior

It would be really helpful if we had the ability to also call [`run_deployment()`](https://orion-docs.prefect.io/api-ref/prefect/deployments/#prefect.deployments.run_deployment) by providing the **deployment id** instead of the deployment name

### Example Use

_No response_

### Additional context

_No response_
Ability to run_deployment by providing deployment id instead of deployment name
### First check

- [X] I added a descriptive title to this issue.
- [X] I used the GitHub search to find a similar request and didn't find it.
- [X] I searched the Prefect documentation for this feature.

### Prefect Version

2.x

### Describe the current behavior

Right now the [`run_deployment()`](https://orion-docs.prefect.io/api-ref/prefect/deployments/#prefect.deployments.run_deployment) function is really useful when we want to start a deployed flow run from the Python API. However it requires us to provide the deployment name in the in the form "/".

### Describe the proposed behavior

It would be really helpful if we had the ability to also call [`run_deployment()`](https://orion-docs.prefect.io/api-ref/prefect/deployments/#prefect.deployments.run_deployment) by providing the **deployment id** instead of the deployment name

### Example Use

_No response_

### Additional context

_No response_


Discussion:
Thanks @andreas-ntonas! This makes sense to me, I think the type can probably just become `Union[str, UUID]` like some of our other deployment interfaces. Can you please update this to include an example usage (e.g. a Python code block) and a case where the ID would be superior to a name?
Thanks @andreas-ntonas! This makes sense to me, I think the type can probably just become `Union[str, UUID]` like some of our other deployment interfaces. Can you please update this to include an example usage (e.g. a Python code block) and a case where the ID would be superior to a name?

Resolving patch:
diff --git a/src/prefect/deployments.py b/src/prefect/deployments.py
--- a/src/prefect/deployments.py
+++ b/src/prefect/deployments.py
@@ -8,7 +8,7 @@
 from datetime import datetime
 from functools import partial
 from pathlib import Path
-from typing import Any, Dict, Iterable, List, Optional
+from typing import Any, Dict, Iterable, List, Optional, Union
 from uuid import UUID
 
 import anyio
@@ -45,7 +45,7 @@
 @sync_compatible
 @inject_client
 async def run_deployment(
-    name: str,
+    name: Union[str, UUID],
     client: Optional[PrefectClient] = None,
     parameters: Optional[dict] = None,
     scheduled_time: Optional[datetime] = None,
@@ -64,7 +64,7 @@ async def run_deployment(
     checking the state of the flow run if completion is important moving forward.
 
     Args:
-        name: The deployment name in the form: '<flow-name>/<deployment-name>'
+        name: The deployment id or deployment name in the form: '<flow-name>/<deployment-name>'
         parameters: Parameter overrides for this flow run. Merged with the deployment
             defaults.
         scheduled_time: The time to schedule the flow run for, defaults to scheduling
@@ -86,7 +86,20 @@ async def run_deployment(
 
     parameters = parameters or {}
 
-    deployment = await client.read_deployment_by_name(name)
+    deployment_id = None
+
+    if isinstance(name, UUID):
+        deployment_id = name
+    else:
+        try:
+            deployment_id = UUID(name)
+        except ValueError:
+            pass
+
+    if deployment_id:
+        deployment = await client.read_deployment(deployment_id=deployment_id)
+    else:
+        deployment = await client.read_deployment_by_name(name)
 
     flow_run_ctx = FlowRunContext.get()
     if flow_run_ctx:
@@ -101,14 +114,20 @@ async def run_deployment(
             k: await collect_task_run_inputs(v) for k, v in parameters.items()
         }
 
+        if deployment_id:
+            flow = await client.read_flow(deployment.flow_id)
+            deployment_name = f"{flow.name}/{deployment.name}"
+        else:
+            deployment_name = name
+
         # Generate a task in the parent flow run to represent the result of the subflow
         dummy_task = Task(
-            name=name,
+            name=deployment_name,
             fn=lambda: None,
             version=deployment.version,
         )
         # Override the default task key to include the deployment name
-        dummy_task.task_key = f"{__name__}.run_deployment.{slugify(name)}"
+        dummy_task.task_key = f"{__name__}.run_deployment.{slugify(deployment_name)}"
         parent_task_run = await client.create_task_run(
             task=dummy_task,
             flow_run_id=flow_run_ctx.flow_run.id,


Test patch:
diff --git a/tests/test_deployments.py b/tests/test_deployments.py
--- a/tests/test_deployments.py
+++ b/tests/test_deployments.py
@@ -756,6 +756,38 @@ async def test_run_deployment_with_ephemeral_api(
         assert flow_run.deployment_id == deployment_id
         assert flow_run.state
 
+    async def test_run_deployment_with_deployment_id_str(
+        self,
+        test_deployment,
+        orion_client,
+    ):
+        _, deployment_id = test_deployment
+
+        flow_run = await run_deployment(
+            f"{deployment_id}",
+            timeout=0,
+            poll_interval=0,
+            client=orion_client,
+        )
+        assert flow_run.deployment_id == deployment_id
+        assert flow_run.state
+
+    async def test_run_deployment_with_deployment_id_uuid(
+        self,
+        test_deployment,
+        orion_client,
+    ):
+        _, deployment_id = test_deployment
+
+        flow_run = await run_deployment(
+            deployment_id,
+            timeout=0,
+            poll_interval=0,
+            client=orion_client,
+        )
+        assert flow_run.deployment_id == deployment_id
+        assert flow_run.state
+
     def test_returns_flow_run_on_timeout(
         self,
         test_deployment,