prefect-client 2.14.20__py3-none-any.whl → 2.15.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. prefect/_internal/concurrency/api.py +37 -2
  2. prefect/_internal/concurrency/calls.py +9 -0
  3. prefect/_internal/concurrency/cancellation.py +3 -1
  4. prefect/_internal/concurrency/event_loop.py +2 -2
  5. prefect/_internal/concurrency/threads.py +3 -2
  6. prefect/_internal/pydantic/annotations/pendulum.py +4 -4
  7. prefect/_internal/pydantic/v2_schema.py +2 -2
  8. prefect/_vendor/fastapi/__init__.py +1 -1
  9. prefect/_vendor/fastapi/applications.py +13 -13
  10. prefect/_vendor/fastapi/background.py +3 -1
  11. prefect/_vendor/fastapi/concurrency.py +7 -3
  12. prefect/_vendor/fastapi/datastructures.py +9 -7
  13. prefect/_vendor/fastapi/dependencies/utils.py +12 -7
  14. prefect/_vendor/fastapi/encoders.py +1 -1
  15. prefect/_vendor/fastapi/exception_handlers.py +7 -4
  16. prefect/_vendor/fastapi/exceptions.py +4 -2
  17. prefect/_vendor/fastapi/middleware/__init__.py +1 -1
  18. prefect/_vendor/fastapi/middleware/asyncexitstack.py +1 -1
  19. prefect/_vendor/fastapi/middleware/cors.py +3 -1
  20. prefect/_vendor/fastapi/middleware/gzip.py +3 -1
  21. prefect/_vendor/fastapi/middleware/httpsredirect.py +1 -1
  22. prefect/_vendor/fastapi/middleware/trustedhost.py +1 -1
  23. prefect/_vendor/fastapi/middleware/wsgi.py +3 -1
  24. prefect/_vendor/fastapi/openapi/docs.py +1 -1
  25. prefect/_vendor/fastapi/openapi/utils.py +3 -3
  26. prefect/_vendor/fastapi/requests.py +4 -2
  27. prefect/_vendor/fastapi/responses.py +13 -7
  28. prefect/_vendor/fastapi/routing.py +15 -15
  29. prefect/_vendor/fastapi/security/api_key.py +3 -3
  30. prefect/_vendor/fastapi/security/http.py +2 -2
  31. prefect/_vendor/fastapi/security/oauth2.py +2 -2
  32. prefect/_vendor/fastapi/security/open_id_connect_url.py +3 -3
  33. prefect/_vendor/fastapi/staticfiles.py +1 -1
  34. prefect/_vendor/fastapi/templating.py +3 -1
  35. prefect/_vendor/fastapi/testclient.py +1 -1
  36. prefect/_vendor/fastapi/utils.py +3 -3
  37. prefect/_vendor/fastapi/websockets.py +7 -3
  38. prefect/_vendor/starlette/__init__.py +1 -0
  39. prefect/_vendor/starlette/_compat.py +28 -0
  40. prefect/_vendor/starlette/_exception_handler.py +80 -0
  41. prefect/_vendor/starlette/_utils.py +88 -0
  42. prefect/_vendor/starlette/applications.py +261 -0
  43. prefect/_vendor/starlette/authentication.py +159 -0
  44. prefect/_vendor/starlette/background.py +43 -0
  45. prefect/_vendor/starlette/concurrency.py +59 -0
  46. prefect/_vendor/starlette/config.py +151 -0
  47. prefect/_vendor/starlette/convertors.py +87 -0
  48. prefect/_vendor/starlette/datastructures.py +707 -0
  49. prefect/_vendor/starlette/endpoints.py +130 -0
  50. prefect/_vendor/starlette/exceptions.py +60 -0
  51. prefect/_vendor/starlette/formparsers.py +276 -0
  52. prefect/_vendor/starlette/middleware/__init__.py +17 -0
  53. prefect/_vendor/starlette/middleware/authentication.py +52 -0
  54. prefect/_vendor/starlette/middleware/base.py +220 -0
  55. prefect/_vendor/starlette/middleware/cors.py +176 -0
  56. prefect/_vendor/starlette/middleware/errors.py +265 -0
  57. prefect/_vendor/starlette/middleware/exceptions.py +74 -0
  58. prefect/_vendor/starlette/middleware/gzip.py +113 -0
  59. prefect/_vendor/starlette/middleware/httpsredirect.py +19 -0
  60. prefect/_vendor/starlette/middleware/sessions.py +82 -0
  61. prefect/_vendor/starlette/middleware/trustedhost.py +64 -0
  62. prefect/_vendor/starlette/middleware/wsgi.py +147 -0
  63. prefect/_vendor/starlette/requests.py +328 -0
  64. prefect/_vendor/starlette/responses.py +347 -0
  65. prefect/_vendor/starlette/routing.py +933 -0
  66. prefect/_vendor/starlette/schemas.py +154 -0
  67. prefect/_vendor/starlette/staticfiles.py +248 -0
  68. prefect/_vendor/starlette/status.py +199 -0
  69. prefect/_vendor/starlette/templating.py +231 -0
  70. prefect/_vendor/starlette/testclient.py +805 -0
  71. prefect/_vendor/starlette/types.py +30 -0
  72. prefect/_vendor/starlette/websockets.py +193 -0
  73. prefect/blocks/core.py +3 -3
  74. prefect/blocks/notifications.py +10 -9
  75. prefect/client/base.py +1 -1
  76. prefect/client/cloud.py +1 -1
  77. prefect/client/orchestration.py +1 -1
  78. prefect/client/schemas/objects.py +11 -0
  79. prefect/client/subscriptions.py +19 -12
  80. prefect/concurrency/services.py +1 -1
  81. prefect/context.py +4 -4
  82. prefect/deployments/deployments.py +3 -3
  83. prefect/engine.py +89 -17
  84. prefect/events/clients.py +1 -1
  85. prefect/events/utilities.py +4 -1
  86. prefect/events/worker.py +10 -6
  87. prefect/filesystems.py +9 -9
  88. prefect/flow_runs.py +5 -1
  89. prefect/futures.py +1 -1
  90. prefect/infrastructure/container.py +3 -3
  91. prefect/infrastructure/kubernetes.py +4 -6
  92. prefect/infrastructure/process.py +3 -3
  93. prefect/input/run_input.py +1 -1
  94. prefect/logging/formatters.py +1 -1
  95. prefect/results.py +3 -6
  96. prefect/runner/server.py +4 -4
  97. prefect/settings.py +23 -3
  98. prefect/software/pip.py +1 -1
  99. prefect/task_engine.py +14 -11
  100. prefect/task_server.py +69 -35
  101. prefect/utilities/asyncutils.py +12 -2
  102. prefect/utilities/collections.py +1 -1
  103. prefect/utilities/filesystem.py +10 -5
  104. {prefect_client-2.14.20.dist-info → prefect_client-2.15.0.dist-info}/METADATA +4 -2
  105. {prefect_client-2.14.20.dist-info → prefect_client-2.15.0.dist-info}/RECORD +108 -73
  106. {prefect_client-2.14.20.dist-info → prefect_client-2.15.0.dist-info}/LICENSE +0 -0
  107. {prefect_client-2.14.20.dist-info → prefect_client-2.15.0.dist-info}/WHEEL +0 -0
  108. {prefect_client-2.14.20.dist-info → prefect_client-2.15.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,30 @@
1
+ import typing
2
+
3
+ if typing.TYPE_CHECKING:
4
+ from prefect._vendor.starlette.requests import Request
5
+ from prefect._vendor.starlette.responses import Response
6
+ from prefect._vendor.starlette.websockets import WebSocket
7
+
8
+ AppType = typing.TypeVar("AppType")
9
+
10
+ Scope = typing.MutableMapping[str, typing.Any]
11
+ Message = typing.MutableMapping[str, typing.Any]
12
+
13
+ Receive = typing.Callable[[], typing.Awaitable[Message]]
14
+ Send = typing.Callable[[Message], typing.Awaitable[None]]
15
+
16
+ ASGIApp = typing.Callable[[Scope, Receive, Send], typing.Awaitable[None]]
17
+
18
+ StatelessLifespan = typing.Callable[[AppType], typing.AsyncContextManager[None]]
19
+ StatefulLifespan = typing.Callable[
20
+ [AppType], typing.AsyncContextManager[typing.Mapping[str, typing.Any]]
21
+ ]
22
+ Lifespan = typing.Union[StatelessLifespan[AppType], StatefulLifespan[AppType]]
23
+
24
+ HTTPExceptionHandler = typing.Callable[
25
+ ["Request", Exception], typing.Union["Response", typing.Awaitable["Response"]]
26
+ ]
27
+ WebSocketExceptionHandler = typing.Callable[
28
+ ["WebSocket", Exception], typing.Awaitable[None]
29
+ ]
30
+ ExceptionHandler = typing.Union[HTTPExceptionHandler, WebSocketExceptionHandler]
@@ -0,0 +1,193 @@
1
+ import enum
2
+ import json
3
+ import typing
4
+
5
+ from prefect._vendor.starlette.requests import HTTPConnection
6
+ from prefect._vendor.starlette.types import Message, Receive, Scope, Send
7
+
8
+
9
+ class WebSocketState(enum.Enum):
10
+ CONNECTING = 0
11
+ CONNECTED = 1
12
+ DISCONNECTED = 2
13
+
14
+
15
+ class WebSocketDisconnect(Exception):
16
+ def __init__(self, code: int = 1000, reason: typing.Optional[str] = None) -> None:
17
+ self.code = code
18
+ self.reason = reason or ""
19
+
20
+
21
+ class WebSocket(HTTPConnection):
22
+ def __init__(self, scope: Scope, receive: Receive, send: Send) -> None:
23
+ super().__init__(scope)
24
+ assert scope["type"] == "websocket"
25
+ self._receive = receive
26
+ self._send = send
27
+ self.client_state = WebSocketState.CONNECTING
28
+ self.application_state = WebSocketState.CONNECTING
29
+
30
+ async def receive(self) -> Message:
31
+ """
32
+ Receive ASGI websocket messages, ensuring valid state transitions.
33
+ """
34
+ if self.client_state == WebSocketState.CONNECTING:
35
+ message = await self._receive()
36
+ message_type = message["type"]
37
+ if message_type != "websocket.connect":
38
+ raise RuntimeError(
39
+ 'Expected ASGI message "websocket.connect", '
40
+ f"but got {message_type!r}"
41
+ )
42
+ self.client_state = WebSocketState.CONNECTED
43
+ return message
44
+ elif self.client_state == WebSocketState.CONNECTED:
45
+ message = await self._receive()
46
+ message_type = message["type"]
47
+ if message_type not in {"websocket.receive", "websocket.disconnect"}:
48
+ raise RuntimeError(
49
+ 'Expected ASGI message "websocket.receive" or '
50
+ f'"websocket.disconnect", but got {message_type!r}'
51
+ )
52
+ if message_type == "websocket.disconnect":
53
+ self.client_state = WebSocketState.DISCONNECTED
54
+ return message
55
+ else:
56
+ raise RuntimeError(
57
+ 'Cannot call "receive" once a disconnect message has been received.'
58
+ )
59
+
60
+ async def send(self, message: Message) -> None:
61
+ """
62
+ Send ASGI websocket messages, ensuring valid state transitions.
63
+ """
64
+ if self.application_state == WebSocketState.CONNECTING:
65
+ message_type = message["type"]
66
+ if message_type not in {"websocket.accept", "websocket.close"}:
67
+ raise RuntimeError(
68
+ 'Expected ASGI message "websocket.accept" or '
69
+ f'"websocket.close", but got {message_type!r}'
70
+ )
71
+ if message_type == "websocket.close":
72
+ self.application_state = WebSocketState.DISCONNECTED
73
+ else:
74
+ self.application_state = WebSocketState.CONNECTED
75
+ await self._send(message)
76
+ elif self.application_state == WebSocketState.CONNECTED:
77
+ message_type = message["type"]
78
+ if message_type not in {"websocket.send", "websocket.close"}:
79
+ raise RuntimeError(
80
+ 'Expected ASGI message "websocket.send" or "websocket.close", '
81
+ f"but got {message_type!r}"
82
+ )
83
+ if message_type == "websocket.close":
84
+ self.application_state = WebSocketState.DISCONNECTED
85
+ await self._send(message)
86
+ else:
87
+ raise RuntimeError('Cannot call "send" once a close message has been sent.')
88
+
89
+ async def accept(
90
+ self,
91
+ subprotocol: typing.Optional[str] = None,
92
+ headers: typing.Optional[typing.Iterable[typing.Tuple[bytes, bytes]]] = None,
93
+ ) -> None:
94
+ headers = headers or []
95
+
96
+ if self.client_state == WebSocketState.CONNECTING:
97
+ # If we haven't yet seen the 'connect' message, then wait for it first.
98
+ await self.receive()
99
+ await self.send(
100
+ {"type": "websocket.accept", "subprotocol": subprotocol, "headers": headers}
101
+ )
102
+
103
+ def _raise_on_disconnect(self, message: Message) -> None:
104
+ if message["type"] == "websocket.disconnect":
105
+ raise WebSocketDisconnect(message["code"], message.get("reason"))
106
+
107
+ async def receive_text(self) -> str:
108
+ if self.application_state != WebSocketState.CONNECTED:
109
+ raise RuntimeError(
110
+ 'WebSocket is not connected. Need to call "accept" first.'
111
+ )
112
+ message = await self.receive()
113
+ self._raise_on_disconnect(message)
114
+ return typing.cast(str, message["text"])
115
+
116
+ async def receive_bytes(self) -> bytes:
117
+ if self.application_state != WebSocketState.CONNECTED:
118
+ raise RuntimeError(
119
+ 'WebSocket is not connected. Need to call "accept" first.'
120
+ )
121
+ message = await self.receive()
122
+ self._raise_on_disconnect(message)
123
+ return typing.cast(bytes, message["bytes"])
124
+
125
+ async def receive_json(self, mode: str = "text") -> typing.Any:
126
+ if mode not in {"text", "binary"}:
127
+ raise RuntimeError('The "mode" argument should be "text" or "binary".')
128
+ if self.application_state != WebSocketState.CONNECTED:
129
+ raise RuntimeError(
130
+ 'WebSocket is not connected. Need to call "accept" first.'
131
+ )
132
+ message = await self.receive()
133
+ self._raise_on_disconnect(message)
134
+
135
+ if mode == "text":
136
+ text = message["text"]
137
+ else:
138
+ text = message["bytes"].decode("utf-8")
139
+ return json.loads(text)
140
+
141
+ async def iter_text(self) -> typing.AsyncIterator[str]:
142
+ try:
143
+ while True:
144
+ yield await self.receive_text()
145
+ except WebSocketDisconnect:
146
+ pass
147
+
148
+ async def iter_bytes(self) -> typing.AsyncIterator[bytes]:
149
+ try:
150
+ while True:
151
+ yield await self.receive_bytes()
152
+ except WebSocketDisconnect:
153
+ pass
154
+
155
+ async def iter_json(self) -> typing.AsyncIterator[typing.Any]:
156
+ try:
157
+ while True:
158
+ yield await self.receive_json()
159
+ except WebSocketDisconnect:
160
+ pass
161
+
162
+ async def send_text(self, data: str) -> None:
163
+ await self.send({"type": "websocket.send", "text": data})
164
+
165
+ async def send_bytes(self, data: bytes) -> None:
166
+ await self.send({"type": "websocket.send", "bytes": data})
167
+
168
+ async def send_json(self, data: typing.Any, mode: str = "text") -> None:
169
+ if mode not in {"text", "binary"}:
170
+ raise RuntimeError('The "mode" argument should be "text" or "binary".')
171
+ text = json.dumps(data, separators=(",", ":"), ensure_ascii=False)
172
+ if mode == "text":
173
+ await self.send({"type": "websocket.send", "text": text})
174
+ else:
175
+ await self.send({"type": "websocket.send", "bytes": text.encode("utf-8")})
176
+
177
+ async def close(
178
+ self, code: int = 1000, reason: typing.Optional[str] = None
179
+ ) -> None:
180
+ await self.send(
181
+ {"type": "websocket.close", "code": code, "reason": reason or ""}
182
+ )
183
+
184
+
185
+ class WebSocketClose:
186
+ def __init__(self, code: int = 1000, reason: typing.Optional[str] = None) -> None:
187
+ self.code = code
188
+ self.reason = reason or ""
189
+
190
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
191
+ await send(
192
+ {"type": "websocket.close", "code": self.code, "reason": self.reason}
193
+ )
prefect/blocks/core.py CHANGED
@@ -257,9 +257,9 @@ class Block(BaseModel, ABC):
257
257
  type_._to_block_schema_reference_dict(),
258
258
  ]
259
259
  else:
260
- refs[field.name] = (
261
- type_._to_block_schema_reference_dict()
262
- )
260
+ refs[
261
+ field.name
262
+ ] = type_._to_block_schema_reference_dict()
263
263
 
264
264
  def __init__(self, *args, **kwargs):
265
265
  super().__init__(*args, **kwargs)
@@ -24,14 +24,14 @@ class AbstractAppriseNotificationBlock(NotificationBlock, ABC):
24
24
  An abstract class for sending notifications using Apprise.
25
25
  """
26
26
 
27
- notify_type: Literal["prefect_default", "info", "success", "warning", "failure"] = (
28
- Field(
29
- default=PREFECT_NOTIFY_TYPE_DEFAULT,
30
- description=(
31
- "The type of notification being performed; the prefect_default "
32
- "is a plain notification that does not attach an image."
33
- ),
34
- )
27
+ notify_type: Literal[
28
+ "prefect_default", "info", "success", "warning", "failure"
29
+ ] = Field(
30
+ default=PREFECT_NOTIFY_TYPE_DEFAULT,
31
+ description=(
32
+ "The type of notification being performed; the prefect_default "
33
+ "is a plain notification that does not attach an image."
34
+ ),
35
35
  )
36
36
 
37
37
  def __init__(self, *args, **kwargs):
@@ -714,7 +714,8 @@ class CustomWebhookNotificationBlock(NotificationBlock):
714
714
 
715
715
  # make request with httpx
716
716
  client = httpx.AsyncClient(headers={"user-agent": "Prefect Notifications"})
717
- resp = await client.request(**self._build_request_args(body, subject))
717
+ async with client:
718
+ resp = await client.request(**self._build_request_args(body, subject))
718
719
  resp.raise_for_status()
719
720
 
720
721
 
prefect/client/base.py CHANGED
@@ -22,7 +22,7 @@ import anyio
22
22
  import httpx
23
23
  from asgi_lifespan import LifespanManager
24
24
  from httpx import HTTPStatusError, Response
25
- from starlette import status
25
+ from prefect._vendor.starlette import status
26
26
  from typing_extensions import Self
27
27
 
28
28
  from prefect.exceptions import PrefectHTTPStatusError
prefect/client/cloud.py CHANGED
@@ -11,7 +11,7 @@ if HAS_PYDANTIC_V2:
11
11
  else:
12
12
  import pydantic
13
13
 
14
- from starlette import status
14
+ from prefect._vendor.starlette import status
15
15
 
16
16
  import prefect.context
17
17
  import prefect.settings
@@ -26,7 +26,7 @@ else:
26
26
  import pydantic
27
27
 
28
28
  from asgi_lifespan import LifespanManager
29
- from starlette import status
29
+ from prefect._vendor.starlette import status
30
30
 
31
31
  import prefect
32
32
  import prefect.exceptions
@@ -97,6 +97,14 @@ class DeploymentStatus(AutoEnum):
97
97
  NOT_READY = AutoEnum.auto()
98
98
 
99
99
 
100
+ class WorkQueueStatus(AutoEnum):
101
+ """Enumeration of work queue statuses."""
102
+
103
+ READY = AutoEnum.auto()
104
+ NOT_READY = AutoEnum.auto()
105
+ PAUSED = AutoEnum.auto()
106
+
107
+
100
108
  class StateDetails(PrefectBaseModel):
101
109
  flow_run_id: UUID = None
102
110
  task_run_id: UUID = None
@@ -1222,6 +1230,9 @@ class WorkQueue(ObjectBaseModel):
1222
1230
  last_polled: Optional[DateTimeTZ] = Field(
1223
1231
  default=None, description="The last time an agent polled this queue for work."
1224
1232
  )
1233
+ status: Optional[WorkQueueStatus] = Field(
1234
+ default=None, description="The queue status."
1235
+ )
1225
1236
 
1226
1237
  @validator("name", check_fields=False)
1227
1238
  def validate_name_characters(cls, v):
@@ -1,25 +1,30 @@
1
1
  import asyncio
2
- from typing import Generic, Type, TypeVar
2
+ from typing import Generic, List, Type, TypeVar
3
3
 
4
4
  import orjson
5
5
  import websockets
6
6
  import websockets.exceptions
7
- from starlette.status import WS_1008_POLICY_VIOLATION
7
+ from prefect._vendor.starlette.status import WS_1008_POLICY_VIOLATION
8
8
  from typing_extensions import Self
9
9
 
10
10
  from prefect._internal.schemas.bases import IDBaseModel
11
+ from prefect.logging import get_logger
11
12
  from prefect.settings import PREFECT_API_KEY, PREFECT_API_URL
12
13
 
14
+ logger = get_logger(__name__)
15
+
13
16
  S = TypeVar("S", bound=IDBaseModel)
14
17
 
15
18
 
16
19
  class Subscription(Generic[S]):
17
- def __init__(self, model: Type[S], path: str):
20
+ def __init__(self, model: Type[S], path: str, keys: List[str]):
18
21
  self.model = model
19
22
 
20
23
  base_url = PREFECT_API_URL.value().replace("http", "ws", 1)
21
24
  self.subscription_url = f"{base_url}{path}"
22
25
 
26
+ self.keys = keys
27
+
23
28
  self._connect = websockets.connect(
24
29
  self.subscription_url,
25
30
  subprotocols=["prefect"],
@@ -35,11 +40,7 @@ class Subscription(Generic[S]):
35
40
  await self._ensure_connected()
36
41
  message = await self._websocket.recv()
37
42
 
38
- message_data = orjson.loads(message)
39
-
40
- if message_data.get("type") == "ping":
41
- await self._websocket.send(orjson.dumps({"type": "pong"}).decode())
42
- continue
43
+ await self._websocket.send(orjson.dumps({"type": "ack"}).decode())
43
44
 
44
45
  return self.model.parse_raw(message)
45
46
  except (
@@ -57,13 +58,19 @@ class Subscription(Generic[S]):
57
58
 
58
59
  websocket = await self._connect.__aenter__()
59
60
 
60
- await websocket.send(
61
- orjson.dumps({"type": "auth", "token": PREFECT_API_KEY.value()}).decode()
62
- )
63
-
64
61
  try:
62
+ await websocket.send(
63
+ orjson.dumps(
64
+ {"type": "auth", "token": PREFECT_API_KEY.value()}
65
+ ).decode()
66
+ )
67
+
65
68
  auth = orjson.loads(await websocket.recv())
66
69
  assert auth["type"] == "auth_success"
70
+
71
+ await websocket.send(
72
+ orjson.dumps({"type": "subscribe", "keys": self.keys}).decode()
73
+ )
67
74
  except (
68
75
  AssertionError,
69
76
  websockets.exceptions.ConnectionClosedError,
@@ -7,7 +7,7 @@ from typing import (
7
7
  )
8
8
 
9
9
  import httpx
10
- from starlette import status
10
+ from prefect._vendor.starlette import status
11
11
 
12
12
  from prefect import get_client
13
13
  from prefect._internal.concurrency import logger
prefect/context.py CHANGED
@@ -137,9 +137,9 @@ class PrefectObjectRegistry(ContextModel):
137
137
  )
138
138
 
139
139
  # Failures will be a tuple of (exception, instance, args, kwargs)
140
- _instance_init_failures: Dict[Type[T], List[Tuple[Exception, T, Tuple, Dict]]] = (
141
- PrivateAttr(default_factory=lambda: defaultdict(list))
142
- )
140
+ _instance_init_failures: Dict[
141
+ Type[T], List[Tuple[Exception, T, Tuple, Dict]]
142
+ ] = PrivateAttr(default_factory=lambda: defaultdict(list))
143
143
 
144
144
  block_code_execution: bool = False
145
145
  capture_failures: bool = False
@@ -236,7 +236,7 @@ class EngineContext(RunContext):
236
236
  autonomous_task_run: Optional[TaskRun] = None
237
237
  task_runner: BaseTaskRunner
238
238
  log_prints: bool = False
239
- parameters: Dict[str, Any]
239
+ parameters: Optional[Dict[str, Any]] = None
240
240
 
241
241
  # Result handling
242
242
  result_factory: ResultFactory
@@ -93,13 +93,13 @@ async def run_deployment(
93
93
  run metadata immediately. Setting `timeout` to None will allow this
94
94
  function to poll indefinitely. Defaults to None.
95
95
  poll_interval: The number of seconds between polls
96
- tags: A list of tags to associate with this flow run; note that tags are used
97
- only for organizational purposes.
96
+ tags: A list of tags to associate with this flow run; tags can be used in
97
+ automations and for organizational purposes.
98
98
  idempotency_key: A unique value to recognize retries of the same run, and
99
99
  prevent creating multiple flow runs.
100
100
  work_queue_name: The name of a work queue to use for this run. Defaults to
101
101
  the default work queue for the deployment.
102
- as_subflow: Whether or not to link the flow run as a subflow of the current
102
+ as_subflow: Whether to link the flow run as a subflow of the current
103
103
  flow or task run.
104
104
  """
105
105
  if timeout is not None and timeout < 0: