prefect-client 3.0.0rc14__py3-none-any.whl → 3.0.0rc15__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.
@@ -16,7 +16,6 @@ import warnings
16
16
  from typing import Any, Callable, List, Optional, Type, TypeVar
17
17
 
18
18
  import pendulum
19
- import wrapt
20
19
  from pydantic import BaseModel
21
20
 
22
21
  from prefect.utilities.callables import get_call_parameters
@@ -273,55 +272,3 @@ def register_renamed_module(old_name: str, new_name: str, start_date: str):
273
272
  DEPRECATED_MODULE_ALIASES.append(
274
273
  AliasedModuleDefinition(old_name, new_name, callback)
275
274
  )
276
-
277
-
278
- class AsyncCompatProxy(wrapt.ObjectProxy):
279
- """
280
- A proxy object that allows for awaiting a method that is no longer async.
281
-
282
- See https://wrapt.readthedocs.io/en/master/wrappers.html#object-proxy for more
283
- """
284
-
285
- def __init__(self, wrapped, class_name: str, method_name: str):
286
- super().__init__(wrapped)
287
- self._self_class_name = class_name
288
- self._self_method_name = method_name
289
- self._self_already_awaited = False
290
-
291
- def __await__(self):
292
- if not self._self_already_awaited:
293
- warnings.warn(
294
- (
295
- f"The {self._self_method_name!r} method on {self._self_class_name!r}"
296
- " is no longer async and awaiting it will raise an error after Dec 2024"
297
- " - please remove the `await` keyword."
298
- ),
299
- DeprecationWarning,
300
- stacklevel=2,
301
- )
302
- self._self_already_awaited = True
303
- yield
304
- return self.__wrapped__
305
-
306
- def __repr__(self):
307
- return repr(self.__wrapped__)
308
-
309
- def __reduce_ex__(self, protocol):
310
- return (
311
- type(self),
312
- (self.__wrapped__,),
313
- {"_self_already_awaited": self._self_already_awaited},
314
- )
315
-
316
-
317
- def deprecated_async_method(wrapped):
318
- """Decorator that wraps a sync method to allow awaiting it even though it is no longer async."""
319
-
320
- @wrapt.decorator
321
- def wrapper(wrapped, instance, args, kwargs):
322
- result = wrapped(*args, **kwargs)
323
- return AsyncCompatProxy(
324
- result, class_name=instance.__class__.__name__, method_name=wrapped.__name__
325
- )
326
-
327
- return wrapper(wrapped)
prefect/context.py CHANGED
@@ -91,11 +91,12 @@ def hydrated_context(
91
91
  client = client or get_client(sync_client=True)
92
92
  if flow_run_context := serialized_context.get("flow_run_context"):
93
93
  flow = flow_run_context["flow"]
94
+ task_runner = stack.enter_context(flow.task_runner.duplicate())
94
95
  flow_run_context = FlowRunContext(
95
96
  **flow_run_context,
96
97
  client=client,
97
98
  result_factory=run_coro_as_sync(ResultFactory.from_flow(flow)),
98
- task_runner=flow.task_runner.duplicate(),
99
+ task_runner=task_runner,
99
100
  detached=True,
100
101
  )
101
102
  stack.enter_context(flow_run_context)
prefect/events/clients.py CHANGED
@@ -15,7 +15,6 @@ from typing import (
15
15
  )
16
16
  from uuid import UUID
17
17
 
18
- import httpx
19
18
  import orjson
20
19
  import pendulum
21
20
  from cachetools import TTLCache
@@ -29,10 +28,14 @@ from websockets.exceptions import (
29
28
  ConnectionClosedOK,
30
29
  )
31
30
 
32
- from prefect.client.base import PrefectHttpxAsyncClient
33
31
  from prefect.events import Event
34
32
  from prefect.logging import get_logger
35
- from prefect.settings import PREFECT_API_KEY, PREFECT_API_URL, PREFECT_CLOUD_API_URL
33
+ from prefect.settings import (
34
+ PREFECT_API_KEY,
35
+ PREFECT_API_URL,
36
+ PREFECT_CLOUD_API_URL,
37
+ PREFECT_SERVER_ALLOW_EPHEMERAL_MODE,
38
+ )
36
39
 
37
40
  if TYPE_CHECKING:
38
41
  from prefect.events.filters import EventFilter
@@ -66,7 +69,7 @@ logger = get_logger(__name__)
66
69
 
67
70
  def get_events_client(
68
71
  reconnection_attempts: int = 10,
69
- checkpoint_every: int = 20,
72
+ checkpoint_every: int = 700,
70
73
  ) -> "EventsClient":
71
74
  api_url = PREFECT_API_URL.value()
72
75
  if isinstance(api_url, str) and api_url.startswith(PREFECT_CLOUD_API_URL.value()):
@@ -74,13 +77,25 @@ def get_events_client(
74
77
  reconnection_attempts=reconnection_attempts,
75
78
  checkpoint_every=checkpoint_every,
76
79
  )
77
- elif PREFECT_API_URL:
80
+ elif api_url:
81
+ return PrefectEventsClient(
82
+ reconnection_attempts=reconnection_attempts,
83
+ checkpoint_every=checkpoint_every,
84
+ )
85
+ elif PREFECT_SERVER_ALLOW_EPHEMERAL_MODE:
86
+ from prefect.server.api.server import SubprocessASGIServer
87
+
88
+ server = SubprocessASGIServer()
89
+ server.start()
78
90
  return PrefectEventsClient(
91
+ api_url=server.api_url,
79
92
  reconnection_attempts=reconnection_attempts,
80
93
  checkpoint_every=checkpoint_every,
81
94
  )
82
95
  else:
83
- return PrefectEphemeralEventsClient()
96
+ raise ValueError(
97
+ "No Prefect API URL provided. Please set PREFECT_API_URL to the address of a running Prefect server."
98
+ )
84
99
 
85
100
 
86
101
  def get_events_subscriber(
@@ -88,20 +103,29 @@ def get_events_subscriber(
88
103
  reconnection_attempts: int = 10,
89
104
  ) -> "PrefectEventSubscriber":
90
105
  api_url = PREFECT_API_URL.value()
91
- if not api_url:
92
- raise ValueError(
93
- "A Prefect server or Prefect Cloud is required to start an event "
94
- "subscriber. Please check the PREFECT_API_URL setting in your profile."
95
- )
96
106
 
97
107
  if isinstance(api_url, str) and api_url.startswith(PREFECT_CLOUD_API_URL.value()):
98
108
  return PrefectCloudEventSubscriber(
99
109
  filter=filter, reconnection_attempts=reconnection_attempts
100
110
  )
101
- else:
111
+ elif api_url:
102
112
  return PrefectEventSubscriber(
103
113
  filter=filter, reconnection_attempts=reconnection_attempts
104
114
  )
115
+ elif PREFECT_SERVER_ALLOW_EPHEMERAL_MODE:
116
+ from prefect.server.api.server import SubprocessASGIServer
117
+
118
+ server = SubprocessASGIServer()
119
+ server.start()
120
+ return PrefectEventSubscriber(
121
+ api_url=server.api_url,
122
+ filter=filter,
123
+ reconnection_attempts=reconnection_attempts,
124
+ )
125
+ else:
126
+ raise ValueError(
127
+ "No Prefect API URL provided. Please set PREFECT_API_URL to the address of a running Prefect server."
128
+ )
105
129
 
106
130
 
107
131
  class EventsClient(abc.ABC):
@@ -201,47 +225,6 @@ def _get_api_url_and_key(
201
225
  return api_url, api_key
202
226
 
203
227
 
204
- class PrefectEphemeralEventsClient(EventsClient):
205
- """A Prefect Events client that sends events to an ephemeral Prefect server"""
206
-
207
- def __init__(self):
208
- if PREFECT_API_KEY.value():
209
- raise ValueError(
210
- "PrefectEphemeralEventsClient cannot be used when PREFECT_API_KEY is set."
211
- " Please use PrefectEventsClient or PrefectCloudEventsClient instead."
212
- )
213
- from prefect.server.api.server import create_app
214
-
215
- app = create_app(ephemeral=True)
216
-
217
- self._http_client = PrefectHttpxAsyncClient(
218
- transport=httpx.ASGITransport(app=app, raise_app_exceptions=False),
219
- base_url="http://ephemeral-prefect/api",
220
- enable_csrf_support=False,
221
- )
222
-
223
- async def __aenter__(self) -> Self:
224
- await super().__aenter__()
225
- await self._http_client.__aenter__()
226
- return self
227
-
228
- async def __aexit__(
229
- self,
230
- exc_type: Optional[Type[Exception]],
231
- exc_val: Optional[Exception],
232
- exc_tb: Optional[TracebackType],
233
- ) -> None:
234
- self._websocket = None
235
- await self._http_client.__aexit__(exc_type, exc_val, exc_tb)
236
- return await super().__aexit__(exc_type, exc_val, exc_tb)
237
-
238
- async def _emit(self, event: Event) -> None:
239
- await self._http_client.post(
240
- "/events",
241
- json=[event.model_dump(mode="json")],
242
- )
243
-
244
-
245
228
  class PrefectEventsClient(EventsClient):
246
229
  """A Prefect Events client that streams events to a Prefect server"""
247
230
 
@@ -252,7 +235,7 @@ class PrefectEventsClient(EventsClient):
252
235
  self,
253
236
  api_url: Optional[str] = None,
254
237
  reconnection_attempts: int = 10,
255
- checkpoint_every: int = 20,
238
+ checkpoint_every: int = 700,
256
239
  ):
257
240
  """
258
241
  Args:
@@ -371,7 +354,7 @@ class PrefectCloudEventsClient(PrefectEventsClient):
371
354
  api_url: Optional[str] = None,
372
355
  api_key: Optional[str] = None,
373
356
  reconnection_attempts: int = 10,
374
- checkpoint_every: int = 20,
357
+ checkpoint_every: int = 700,
375
358
  ):
376
359
  """
377
360
  Args:
@@ -435,9 +418,9 @@ class PrefectEventSubscriber:
435
418
  reconnection_attempts: When the client is disconnected, how many times
436
419
  the client should attempt to reconnect
437
420
  """
421
+ self._api_key = None
438
422
  if not api_url:
439
423
  api_url = cast(str, PREFECT_API_URL.value())
440
- self._api_key = None
441
424
 
442
425
  from prefect.events.filters import EventFilter
443
426
 
@@ -8,7 +8,6 @@ from pydantic_extra_types.pendulum_dt import DateTime
8
8
  from .clients import (
9
9
  AssertingEventsClient,
10
10
  PrefectCloudEventsClient,
11
- PrefectEphemeralEventsClient,
12
11
  PrefectEventsClient,
13
12
  )
14
13
  from .schemas.events import Event, RelatedResource
@@ -53,7 +52,6 @@ def emit_event(
53
52
  AssertingEventsClient,
54
53
  PrefectCloudEventsClient,
55
54
  PrefectEventsClient,
56
- PrefectEphemeralEventsClient,
57
55
  ]
58
56
  worker_instance = EventsWorker.instance()
59
57
 
prefect/flows.py CHANGED
@@ -66,6 +66,7 @@ from prefect.exceptions import (
66
66
  ObjectNotFound,
67
67
  ParameterTypeError,
68
68
  ScriptError,
69
+ TerminationSignal,
69
70
  UnspecifiedFlowError,
70
71
  )
71
72
  from prefect.filesystems import LocalFileSystem, ReadableDeploymentStorage
@@ -946,10 +947,15 @@ class Flow(Generic[P, R]):
946
947
  else:
947
948
  raise
948
949
 
949
- if loop is not None:
950
- loop.run_until_complete(runner.start(webserver=webserver))
951
- else:
952
- asyncio.run(runner.start(webserver=webserver))
950
+ try:
951
+ if loop is not None:
952
+ loop.run_until_complete(runner.start(webserver=webserver))
953
+ else:
954
+ asyncio.run(runner.start(webserver=webserver))
955
+ except (KeyboardInterrupt, TerminationSignal) as exc:
956
+ logger.info(f"Received {type(exc).__name__}, shutting down...")
957
+ if loop is not None:
958
+ loop.stop()
953
959
 
954
960
  @classmethod
955
961
  @sync_compatible
prefect/futures.py CHANGED
@@ -10,7 +10,6 @@ from typing import Any, Callable, Generic, List, Optional, Set, Union, cast
10
10
 
11
11
  from typing_extensions import TypeVar
12
12
 
13
- from prefect._internal.compatibility.deprecated import deprecated_async_method
14
13
  from prefect.client.orchestration import get_client
15
14
  from prefect.client.schemas.objects import TaskRun
16
15
  from prefect.exceptions import ObjectNotFound
@@ -135,7 +134,6 @@ class PrefectConcurrentFuture(PrefectWrappedFuture[R, concurrent.futures.Future]
135
134
  when the task run is submitted to a ThreadPoolExecutor.
136
135
  """
137
136
 
138
- @deprecated_async_method
139
137
  def wait(self, timeout: Optional[float] = None) -> None:
140
138
  try:
141
139
  result = self._wrapped_future.result(timeout=timeout)
@@ -144,7 +142,6 @@ class PrefectConcurrentFuture(PrefectWrappedFuture[R, concurrent.futures.Future]
144
142
  if isinstance(result, State):
145
143
  self._final_state = result
146
144
 
147
- @deprecated_async_method
148
145
  def result(
149
146
  self,
150
147
  timeout: Optional[float] = None,
@@ -198,7 +195,6 @@ class PrefectDistributedFuture(PrefectFuture[R]):
198
195
  done_callbacks: List[Callable[[PrefectFuture], None]] = []
199
196
  waiter = None
200
197
 
201
- @deprecated_async_method
202
198
  def wait(self, timeout: Optional[float] = None) -> None:
203
199
  return run_coro_as_sync(self.wait_async(timeout=timeout))
204
200
 
@@ -235,7 +231,6 @@ class PrefectDistributedFuture(PrefectFuture[R]):
235
231
  self._final_state = task_run.state
236
232
  return
237
233
 
238
- @deprecated_async_method
239
234
  def result(
240
235
  self,
241
236
  timeout: Optional[float] = None,
prefect/profiles.toml CHANGED
@@ -10,5 +10,8 @@ PREFECT_SERVER_ALLOW_EPHEMERAL_MODE = "true"
10
10
  # You will need to set these values appropriately for your local development environment
11
11
  PREFECT_API_URL = "http://127.0.0.1:4200/api"
12
12
 
13
+ [profiles.test]
14
+ PREFECT_SERVER_ALLOW_EPHEMERAL_MODE = "true"
15
+ PREFECT_API_DATABASE_CONNECTION_URL = "sqlite+aiosqlite:///:memory:"
13
16
 
14
17
  [profiles.cloud]
prefect/runner/storage.py CHANGED
@@ -280,6 +280,10 @@ class GitRepository:
280
280
  "branch": self._branch,
281
281
  }
282
282
  }
283
+ if self._include_submodules:
284
+ pull_step["prefect.deployments.steps.git_clone"][
285
+ "include_submodules"
286
+ ] = self._include_submodules
283
287
  if isinstance(self._credentials, Block):
284
288
  pull_step["prefect.deployments.steps.git_clone"][
285
289
  "credentials"
prefect/settings.py CHANGED
@@ -351,6 +351,7 @@ def warn_on_database_password_value_without_usage(values):
351
351
  if (
352
352
  value
353
353
  and not value.startswith(OBFUSCATED_PREFIX)
354
+ and values["PREFECT_API_DATABASE_CONNECTION_URL"] is not None
354
355
  and (
355
356
  "PREFECT_API_DATABASE_PASSWORD"
356
357
  not in values["PREFECT_API_DATABASE_CONNECTION_URL"]
@@ -403,7 +404,38 @@ def warn_on_misconfigured_api_url(values):
403
404
  return values
404
405
 
405
406
 
406
- def default_database_connection_url(settings, value):
407
+ def default_database_connection_url(settings: "Settings", value: Optional[str]):
408
+ driver = PREFECT_API_DATABASE_DRIVER.value_from(settings)
409
+ if driver == "postgresql+asyncpg":
410
+ required = [
411
+ PREFECT_API_DATABASE_HOST,
412
+ PREFECT_API_DATABASE_USER,
413
+ PREFECT_API_DATABASE_NAME,
414
+ PREFECT_API_DATABASE_PASSWORD,
415
+ ]
416
+ missing = [
417
+ setting.name for setting in required if not setting.value_from(settings)
418
+ ]
419
+ if missing:
420
+ raise ValueError(
421
+ f"Missing required database connection settings: {', '.join(missing)}"
422
+ )
423
+
424
+ host = PREFECT_API_DATABASE_HOST.value_from(settings)
425
+ port = PREFECT_API_DATABASE_PORT.value_from(settings) or 5432
426
+ user = PREFECT_API_DATABASE_USER.value_from(settings)
427
+ name = PREFECT_API_DATABASE_NAME.value_from(settings)
428
+ password = PREFECT_API_DATABASE_PASSWORD.value_from(settings)
429
+
430
+ return f"{driver}://{user}:{password}@{host}:{port}/{name}"
431
+
432
+ elif driver == "sqlite+aiosqlite":
433
+ path = PREFECT_API_DATABASE_NAME.value_from(settings)
434
+ if path:
435
+ return f"{driver}:///{path}"
436
+ elif driver:
437
+ raise ValueError(f"Unsupported database driver: {driver}")
438
+
407
439
  templater = template_with_settings(PREFECT_HOME, PREFECT_API_DATABASE_PASSWORD)
408
440
 
409
441
  # If the user has provided a value, use it
@@ -941,17 +973,6 @@ backend on application startup. If not set, block types must be manually
941
973
  registered.
942
974
  """
943
975
 
944
- PREFECT_API_DATABASE_PASSWORD = Setting(
945
- Optional[str],
946
- default=None,
947
- is_secret=True,
948
- )
949
- """
950
- Password to template into the `PREFECT_API_DATABASE_CONNECTION_URL`.
951
- This is useful if the password must be provided separately from the connection URL.
952
- To use this setting, you must include it in your connection URL.
953
- """
954
-
955
976
  PREFECT_API_DATABASE_CONNECTION_URL = Setting(
956
977
  Optional[str],
957
978
  default=None,
@@ -981,6 +1002,46 @@ PREFECT_API_DATABASE_CONNECTION_URL='postgresql+asyncpg://postgres:${PREFECT_API
981
1002
  ```
982
1003
  """
983
1004
 
1005
+ PREFECT_API_DATABASE_DRIVER = Setting(
1006
+ Optional[Literal["postgresql+asyncpg", "sqlite+aiosqlite"]],
1007
+ default=None,
1008
+ )
1009
+ """
1010
+ The database driver to use when connecting to the database.
1011
+ """
1012
+
1013
+ PREFECT_API_DATABASE_HOST = Setting(Optional[str], default=None)
1014
+ """
1015
+ The database server host.
1016
+ """
1017
+
1018
+ PREFECT_API_DATABASE_PORT = Setting(Optional[int], default=None)
1019
+ """
1020
+ The database server port.
1021
+ """
1022
+
1023
+ PREFECT_API_DATABASE_USER = Setting(Optional[str], default=None)
1024
+ """
1025
+ The user to use when connecting to the database.
1026
+ """
1027
+
1028
+ PREFECT_API_DATABASE_NAME = Setting(Optional[str], default=None)
1029
+ """
1030
+ The name of the Prefect database on the remote server, or the path to the database file
1031
+ for SQLite.
1032
+ """
1033
+
1034
+ PREFECT_API_DATABASE_PASSWORD = Setting(
1035
+ Optional[str],
1036
+ default=None,
1037
+ is_secret=True,
1038
+ )
1039
+ """
1040
+ Password to template into the `PREFECT_API_DATABASE_CONNECTION_URL`.
1041
+ This is useful if the password must be provided separately from the connection URL.
1042
+ To use this setting, you must include it in your connection URL.
1043
+ """
1044
+
984
1045
  PREFECT_API_DATABASE_ECHO = Setting(
985
1046
  bool,
986
1047
  default=False,
prefect/task_engine.py CHANGED
@@ -409,6 +409,22 @@ class SyncTaskRunEngine(BaseTaskRunEngine[P, R]):
409
409
  self.task_run.state_id = new_state.id
410
410
  self.task_run.state_type = new_state.type
411
411
  self.task_run.state_name = new_state.name
412
+
413
+ if new_state.is_final():
414
+ if (
415
+ isinstance(state.data, BaseResult)
416
+ and state.data.has_cached_object()
417
+ ):
418
+ # Avoid fetching the result unless it is cached, otherwise we defeat
419
+ # the purpose of disabling `cache_result_in_memory`
420
+ result = state.result(raise_on_failure=False, fetch=True)
421
+ if inspect.isawaitable(result):
422
+ result = run_coro_as_sync(result)
423
+ else:
424
+ result = state.data
425
+
426
+ link_state_to_result(state, result)
427
+
412
428
  else:
413
429
  try:
414
430
  new_state = propose_state_sync(
@@ -674,6 +690,12 @@ class SyncTaskRunEngine(BaseTaskRunEngine[P, R]):
674
690
  task_run_name=task_run_name,
675
691
  )
676
692
  )
693
+ # Emit an event to capture that the task run was in the `PENDING` state.
694
+ self._last_event = emit_task_run_state_change_event(
695
+ task_run=self.task_run,
696
+ initial_state=None,
697
+ validated_state=self.task_run.state,
698
+ )
677
699
  else:
678
700
  if not self.task_run:
679
701
  self.task_run = run_coro_as_sync(
@@ -686,12 +708,12 @@ class SyncTaskRunEngine(BaseTaskRunEngine[P, R]):
686
708
  extra_task_inputs=dependencies,
687
709
  )
688
710
  )
689
- # Emit an event to capture that the task run was in the `PENDING` state.
690
- self._last_event = emit_task_run_state_change_event(
691
- task_run=self.task_run,
692
- initial_state=None,
693
- validated_state=self.task_run.state,
694
- )
711
+ # Emit an event to capture that the task run was in the `PENDING` state.
712
+ self._last_event = emit_task_run_state_change_event(
713
+ task_run=self.task_run,
714
+ initial_state=None,
715
+ validated_state=self.task_run.state,
716
+ )
695
717
 
696
718
  with self.setup_run_context():
697
719
  # setup_run_context might update the task run name, so log creation here
@@ -966,6 +988,20 @@ class AsyncTaskRunEngine(BaseTaskRunEngine[P, R]):
966
988
  self.task_run.state_id = new_state.id
967
989
  self.task_run.state_type = new_state.type
968
990
  self.task_run.state_name = new_state.name
991
+
992
+ if new_state.is_final():
993
+ if (
994
+ isinstance(new_state.data, BaseResult)
995
+ and new_state.data.has_cached_object()
996
+ ):
997
+ # Avoid fetching the result unless it is cached, otherwise we defeat
998
+ # the purpose of disabling `cache_result_in_memory`
999
+ result = await new_state.result(raise_on_failure=False, fetch=True)
1000
+ else:
1001
+ result = new_state.data
1002
+
1003
+ link_state_to_result(new_state, result)
1004
+
969
1005
  else:
970
1006
  try:
971
1007
  new_state = await propose_state(
@@ -1222,6 +1258,12 @@ class AsyncTaskRunEngine(BaseTaskRunEngine[P, R]):
1222
1258
  extra_task_inputs=dependencies,
1223
1259
  task_run_name=task_run_name,
1224
1260
  )
1261
+ # Emit an event to capture that the task run was in the `PENDING` state.
1262
+ self._last_event = emit_task_run_state_change_event(
1263
+ task_run=self.task_run,
1264
+ initial_state=None,
1265
+ validated_state=self.task_run.state,
1266
+ )
1225
1267
  else:
1226
1268
  if not self.task_run:
1227
1269
  self.task_run = await self.task.create_run(
@@ -1232,12 +1274,12 @@ class AsyncTaskRunEngine(BaseTaskRunEngine[P, R]):
1232
1274
  wait_for=self.wait_for,
1233
1275
  extra_task_inputs=dependencies,
1234
1276
  )
1235
- # Emit an event to capture that the task run was in the `PENDING` state.
1236
- self._last_event = emit_task_run_state_change_event(
1237
- task_run=self.task_run,
1238
- initial_state=None,
1239
- validated_state=self.task_run.state,
1240
- )
1277
+ # Emit an event to capture that the task run was in the `PENDING` state.
1278
+ self._last_event = emit_task_run_state_change_event(
1279
+ task_run=self.task_run,
1280
+ initial_state=None,
1281
+ validated_state=self.task_run.state,
1282
+ )
1241
1283
 
1242
1284
  async with self.setup_run_context():
1243
1285
  # setup_run_context might update the task run name, so log creation here
prefect/task_worker.py CHANGED
@@ -293,12 +293,15 @@ class TaskWorker:
293
293
  await self._client._client.delete(f"/task_runs/{task_run.id}")
294
294
  return
295
295
 
296
+ initial_state = task_run.state
297
+
296
298
  if PREFECT_EXPERIMENTAL_ENABLE_CLIENT_SIDE_TASK_ORCHESTRATION:
297
299
  new_state = Pending()
298
300
  new_state.state_details.deferred = True
299
301
  new_state.state_details.task_run_id = task_run.id
300
302
  new_state.state_details.flow_run_id = task_run.flow_run_id
301
303
  state = new_state
304
+ task_run.state = state
302
305
  else:
303
306
  try:
304
307
  new_state = Pending()
@@ -330,7 +333,7 @@ class TaskWorker:
330
333
 
331
334
  emit_task_run_state_change_event(
332
335
  task_run=task_run,
333
- initial_state=task_run.state,
336
+ initial_state=initial_state,
334
337
  validated_state=state,
335
338
  )
336
339
 
prefect/tasks.py CHANGED
@@ -33,9 +33,6 @@ from uuid import UUID, uuid4
33
33
  from typing_extensions import Literal, ParamSpec
34
34
 
35
35
  import prefect.states
36
- from prefect._internal.compatibility.deprecated import (
37
- deprecated_async_method,
38
- )
39
36
  from prefect.cache_policies import DEFAULT, NONE, CachePolicy
40
37
  from prefect.client.orchestration import get_client
41
38
  from prefect.client.schemas import TaskRun
@@ -1038,7 +1035,6 @@ class Task(Generic[P, R]):
1038
1035
  ) -> State[T]:
1039
1036
  ...
1040
1037
 
1041
- @deprecated_async_method
1042
1038
  def submit(
1043
1039
  self,
1044
1040
  *args: Any,
@@ -1203,7 +1199,6 @@ class Task(Generic[P, R]):
1203
1199
  ) -> PrefectFutureList[State[T]]:
1204
1200
  ...
1205
1201
 
1206
- @deprecated_async_method
1207
1202
  def map(
1208
1203
  self,
1209
1204
  *args: Any,
@@ -1455,6 +1450,15 @@ class Task(Generic[P, R]):
1455
1450
  )
1456
1451
  ) # type: ignore
1457
1452
 
1453
+ from prefect.utilities.engine import emit_task_run_state_change_event
1454
+
1455
+ # emit a `SCHEDULED` event for the task run
1456
+ emit_task_run_state_change_event(
1457
+ task_run=task_run,
1458
+ initial_state=None,
1459
+ validated_state=task_run.state,
1460
+ )
1461
+
1458
1462
  if task_run_url := url_for(task_run):
1459
1463
  logger.info(
1460
1464
  f"Created task run {task_run.name!r}. View it in the UI at {task_run_url!r}"
@@ -30,7 +30,6 @@ import anyio.abc
30
30
  import anyio.from_thread
31
31
  import anyio.to_thread
32
32
  import sniffio
33
- import wrapt
34
33
  from typing_extensions import Literal, ParamSpec, TypeGuard
35
34
 
36
35
  from prefect._internal.concurrency.api import _cast_to_call, from_sync
@@ -210,11 +209,6 @@ def run_coro_as_sync(
210
209
  Returns:
211
210
  The result of the coroutine if wait_for_result is True, otherwise None.
212
211
  """
213
- if not asyncio.iscoroutine(coroutine):
214
- if isinstance(coroutine, wrapt.ObjectProxy):
215
- return coroutine.__wrapped__
216
- else:
217
- raise TypeError("`coroutine` must be a coroutine object")
218
212
 
219
213
  async def coroutine_wrapper() -> Union[R, None]:
220
214
  """
@@ -783,6 +783,9 @@ def emit_task_run_state_change_event(
783
783
  "state_type",
784
784
  "state_name",
785
785
  "state",
786
+ # server materialized fields
787
+ "estimated_start_time_delta",
788
+ "estimated_run_time",
786
789
  },
787
790
  ),
788
791
  },
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prefect-client
3
- Version: 3.0.0rc14
3
+ Version: 3.0.0rc15
4
4
  Summary: Workflow orchestration and management.
5
5
  Home-page: https://www.prefect.io
6
6
  Author: Prefect Technologies, Inc.
@@ -24,47 +24,46 @@ Classifier: Topic :: Software Development :: Libraries
24
24
  Requires-Python: >=3.9
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE
27
- Requires-Dist: anyio <5.0.0,>=4.4.0
28
- Requires-Dist: asgi-lifespan <3.0,>=1.0
29
- Requires-Dist: cachetools <6.0,>=5.3
30
- Requires-Dist: cloudpickle <4.0,>=2.0
31
- Requires-Dist: coolname <3.0.0,>=1.0.4
32
- Requires-Dist: croniter <4.0.0,>=1.0.12
33
- Requires-Dist: exceptiongroup >=1.0.0
34
- Requires-Dist: fastapi <1.0.0,>=0.111.0
35
- Requires-Dist: fsspec >=2022.5.0
36
- Requires-Dist: graphviz >=0.20.1
37
- Requires-Dist: griffe <0.48.0,>=0.20.0
38
- Requires-Dist: httpcore <2.0.0,>=1.0.5
39
- Requires-Dist: httpx[http2] !=0.23.2,>=0.23
40
- Requires-Dist: importlib-resources <6.2.0,>=6.1.3
41
- Requires-Dist: jsonpatch <2.0,>=1.32
42
- Requires-Dist: jsonschema <5.0.0,>=4.0.0
43
- Requires-Dist: orjson <4.0,>=3.7
44
- Requires-Dist: packaging <24.3,>=21.3
45
- Requires-Dist: pathspec >=0.8.0
46
- Requires-Dist: pendulum <4,>=3.0.0
47
- Requires-Dist: prometheus-client >=0.20.0
48
- Requires-Dist: pydantic <3.0.0,>=2.7
49
- Requires-Dist: pydantic-core <3.0.0,>=2.12.0
50
- Requires-Dist: pydantic-extra-types <3.0.0,>=2.8.2
27
+ Requires-Dist: anyio<5.0.0,>=4.4.0
28
+ Requires-Dist: asgi-lifespan<3.0,>=1.0
29
+ Requires-Dist: cachetools<6.0,>=5.3
30
+ Requires-Dist: cloudpickle<4.0,>=2.0
31
+ Requires-Dist: coolname<3.0.0,>=1.0.4
32
+ Requires-Dist: croniter<4.0.0,>=1.0.12
33
+ Requires-Dist: exceptiongroup>=1.0.0
34
+ Requires-Dist: fastapi<1.0.0,>=0.111.0
35
+ Requires-Dist: fsspec>=2022.5.0
36
+ Requires-Dist: graphviz>=0.20.1
37
+ Requires-Dist: griffe<0.48.0,>=0.20.0
38
+ Requires-Dist: httpcore<2.0.0,>=1.0.5
39
+ Requires-Dist: httpx[http2]!=0.23.2,>=0.23
40
+ Requires-Dist: importlib-resources<6.2.0,>=6.1.3
41
+ Requires-Dist: jsonpatch<2.0,>=1.32
42
+ Requires-Dist: jsonschema<5.0.0,>=4.0.0
43
+ Requires-Dist: orjson<4.0,>=3.7
44
+ Requires-Dist: packaging<24.3,>=21.3
45
+ Requires-Dist: pathspec>=0.8.0
46
+ Requires-Dist: pendulum<4,>=3.0.0
47
+ Requires-Dist: prometheus-client>=0.20.0
48
+ Requires-Dist: pydantic<3.0.0,>=2.7
49
+ Requires-Dist: pydantic-core<3.0.0,>=2.12.0
50
+ Requires-Dist: pydantic-extra-types<3.0.0,>=2.8.2
51
51
  Requires-Dist: pydantic-settings
52
- Requires-Dist: python-dateutil <3.0.0,>=2.8.2
53
- Requires-Dist: python-slugify <9.0,>=5.0
54
- Requires-Dist: pyyaml <7.0.0,>=5.4.1
55
- Requires-Dist: rfc3339-validator <0.2.0,>=0.1.4
56
- Requires-Dist: rich <14.0,>=11.0
57
- Requires-Dist: ruamel.yaml >=0.17.0
58
- Requires-Dist: sniffio <2.0.0,>=1.3.0
59
- Requires-Dist: toml >=0.10.0
60
- Requires-Dist: typing-extensions <5.0.0,>=4.5.0
61
- Requires-Dist: ujson <6.0.0,>=5.8.0
62
- Requires-Dist: uvicorn !=0.29.0,>=0.14.0
63
- Requires-Dist: websockets <13.0,>=10.4
64
- Requires-Dist: wrapt >=1.16.0
65
- Requires-Dist: importlib-metadata >=4.4 ; python_version < "3.10"
52
+ Requires-Dist: python-dateutil<3.0.0,>=2.8.2
53
+ Requires-Dist: python-slugify<9.0,>=5.0
54
+ Requires-Dist: pyyaml<7.0.0,>=5.4.1
55
+ Requires-Dist: rfc3339-validator<0.2.0,>=0.1.4
56
+ Requires-Dist: rich<14.0,>=11.0
57
+ Requires-Dist: ruamel.yaml>=0.17.0
58
+ Requires-Dist: sniffio<2.0.0,>=1.3.0
59
+ Requires-Dist: toml>=0.10.0
60
+ Requires-Dist: typing-extensions<5.0.0,>=4.5.0
61
+ Requires-Dist: ujson<6.0.0,>=5.8.0
62
+ Requires-Dist: uvicorn!=0.29.0,>=0.14.0
63
+ Requires-Dist: websockets<13.0,>=10.4
64
+ Requires-Dist: importlib-metadata>=4.4; python_version < "3.10"
66
65
  Provides-Extra: notifications
67
- Requires-Dist: apprise <2.0.0,>=1.1.0 ; extra == 'notifications'
66
+ Requires-Dist: apprise<2.0.0,>=1.1.0; extra == "notifications"
68
67
 
69
68
  <p align="center"><img src="https://github.com/PrefectHQ/prefect/assets/3407835/c654cbc6-63e8-4ada-a92a-efd2f8f24b85" width=1000></p>
70
69
 
@@ -5,28 +5,28 @@ prefect/agent.py,sha256=BOVVY5z-vUIQ2u8LwMTXDaNys2fjOZSS5YGDwJmTQjI,230
5
5
  prefect/artifacts.py,sha256=wet3coxBtqK0914uTf-slYpXRVP0mjbZn804hXB-RS4,13011
6
6
  prefect/automations.py,sha256=NlQ62GPJzy-gnWQqX7c6CQJKw7p60WLGDAFcy82vtg4,5613
7
7
  prefect/cache_policies.py,sha256=uEKNGO-PJ3N35B2tjhRDtQULN6ok72D9raIoJaUyXk0,6365
8
- prefect/context.py,sha256=qX9NSMO4dsxwEkR5FnddSdtcZ-5gJ-0rLz02uWkwGCc,21796
8
+ prefect/context.py,sha256=Q04o0F1zc9O9y7H0Y6po1hvyajrviYAzuQmpKdNvgbM,21859
9
9
  prefect/engine.py,sha256=BpmDbe6miZcTl1vRkxfCPYcWSXADLigGPCagFwucMz0,1976
10
10
  prefect/exceptions.py,sha256=3s69Z_IC3HKF6BKxcHrMPXkKdYwfbEfaTjy4-5LOtQ0,11132
11
11
  prefect/filesystems.py,sha256=rbFvlqHXeeo71nK1Y5I0-ucmGOYUcdkbb6N2vpsRcWE,17229
12
12
  prefect/flow_engine.py,sha256=c8mIffc57zLtHFRo4sVtQOXGihVA_y2mZiXYzjJlOHY,29445
13
13
  prefect/flow_runs.py,sha256=EaXRIQTOnwnA0fO7_EjwafFRmS57K_CRy0Xsz3JDIhc,16070
14
- prefect/flows.py,sha256=MMlHqts-yZA6rMRa5xPHLo_yeaSZ7LjDBJ8dYVS0vCo,90248
15
- prefect/futures.py,sha256=vDSDt5Kc7EVJQTxfA0r4Ul7sy6qOxwz4lkys0tpdngU,16403
14
+ prefect/flows.py,sha256=KIcHBwxEEjC78gzbvMq2-ed7Dic9qEsgJD1t4rBeFwA,90499
15
+ prefect/futures.py,sha256=Zt5U7PnNpKUQuyfAhWAZZxpG0hQ6HXuA4KVg6E9sQf8,16208
16
16
  prefect/main.py,sha256=bab5nBn37a6gmxdPbTlRS2a9Cf0KY0GaCotDOSbcQ7M,1930
17
17
  prefect/manifests.py,sha256=477XcmfdC_yE81wT6zIAKnEUEJ0lH9ZLfOVSgX2FohE,676
18
18
  prefect/plugins.py,sha256=7AICJzHIu8iAeF9vl9wAYm28pR_k7dkdnm3OyJRfCv4,2229
19
- prefect/profiles.toml,sha256=7hwFMmUjLkoUxDj1Ggw0MPxViK9zMjMXmmUFtXLeijU,392
19
+ prefect/profiles.toml,sha256=kTvqDNMzjH3fsm5OEI-NKY4dMmipor5EvQXRB6rPEjY,522
20
20
  prefect/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  prefect/results.py,sha256=3mVkVWZn_VSQ9Pik79StNy113rB_SEiP83SdoUsFvTM,24635
22
22
  prefect/serializers.py,sha256=Lo41EM0_qGzcfB_63390Izeo3DdK6cY6VZfxa9hpSGQ,8712
23
- prefect/settings.py,sha256=ANN3aaQdLZUWBy1UpDvSwxpU-_4c3VL81gG0v3JGjpA,69794
23
+ prefect/settings.py,sha256=QbRNH9kMWGqgnUyl8KuUKsXdLgMOxO-Q5roK-jFmyoM,71780
24
24
  prefect/states.py,sha256=lw22xucH46cN9stkxiV9ByIvq689mH5iL3gErri-Y18,22207
25
- prefect/task_engine.py,sha256=KVkGjD9kcNw4j0YYiVmBGkfb8TpGatEF4qiZDoFDz9c,63227
25
+ prefect/task_engine.py,sha256=JMXoW8qcCTzLtPQY6WU1IqkVfDpHdvFcKBLgehOseUY,65323
26
26
  prefect/task_runners.py,sha256=W1n0yMwbDIqnvffFVJADo9MGEbLaYkzWk52rqgnkMY4,15019
27
27
  prefect/task_runs.py,sha256=jkaQOkRKOHS8fgHUijteriFpjMSKv4zldn1D8tZHkUI,8777
28
- prefect/task_worker.py,sha256=LKyJI5iZueGR7sw_bJIn013PVoRr1aab26F5DYChRGo,17918
29
- prefect/tasks.py,sha256=A-sQB8S5dxcLtl10crDThsfdKpMzm9Rknfwhu27rnvY,68085
28
+ prefect/task_worker.py,sha256=DX4NYERghB8RZeFleZE0xOq3yJVunjUaAKHtiz8wuRo,17992
29
+ prefect/tasks.py,sha256=tpYQhH4wZcOeVTOOGus0Med4prLlmMM2jSf3TKuFdUQ,68230
30
30
  prefect/transactions.py,sha256=XBbOjAUnDWw9QcxVwEamRaWxvRA_Ao-MkIN5dFL7h54,10008
31
31
  prefect/variables.py,sha256=-t5LVY0N-K4f0fa6YwruVVQqwnU3fGWBMYXXE32XPkA,4821
32
32
  prefect/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -35,7 +35,7 @@ prefect/_internal/integrations.py,sha256=U4cZMDbnilzZSKaMxvzZcSL27a1tzRMjDoTfr2u
35
35
  prefect/_internal/pytz.py,sha256=WWl9x16rKFWequGmcOGs_ljpCDPf2LDHMyZp_4D8e6c,13748
36
36
  prefect/_internal/retries.py,sha256=8uuagUX32w5YANLHqjM_1hHmVe9b1HxcwuPMXb1G2Qk,2317
37
37
  prefect/_internal/compatibility/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- prefect/_internal/compatibility/deprecated.py,sha256=7vqE1_PAPS0cDalTfTumHWUIOqIzkbKvQl1iwHlfynQ,9205
38
+ prefect/_internal/compatibility/deprecated.py,sha256=nqevphK00rakKgCfkbqBQ4NCktdb4338uuROjFcq6xA,7517
39
39
  prefect/_internal/compatibility/experimental.py,sha256=nrIeeAe1vZ0yMb1cPw5AroVR6_msx-bzTeBLzY4au6o,5634
40
40
  prefect/_internal/compatibility/migration.py,sha256=O9HrcqxfQ-RrIklH0uGxeXMrQejPz1hmsgrw8zDLJuw,6801
41
41
  prefect/_internal/concurrency/__init__.py,sha256=YlTwU9ryjPNwbJa45adLJY00t_DGCh1QrdtY9WdVFfw,2140
@@ -105,10 +105,10 @@ prefect/docker/__init__.py,sha256=jumlacz2HY9l1ee0L9_kE0PFi9NO3l3pWINm9T5N9hs,52
105
105
  prefect/docker/docker_image.py,sha256=Y84_ooCYA9NGl6FElJul9-FaW3teT-eia2SiNtZ1LG8,2999
106
106
  prefect/events/__init__.py,sha256=GtKl2bE--pJduTxelH2xy7SadlLJmmis8WR1EYixhuA,2094
107
107
  prefect/events/actions.py,sha256=4kBV2NwFlC6oXVeMp9Qb2HMNqv1IZ7FcOqeXz1zlRf0,8983
108
- prefect/events/clients.py,sha256=U3NrU8lqQv_tbkhOa9yq9lo_f082RYt19Pehjnc97Vk,21605
108
+ prefect/events/clients.py,sha256=Vu2ygDPrkQ-uEimdATiMpqa8-k3E7Tvy94O8IoA1VmY,20936
109
109
  prefect/events/filters.py,sha256=IJ1TF-TCC7Wk2nJsbYW-HyAANToDQ6z1MdD63qE-lfw,8186
110
110
  prefect/events/related.py,sha256=1rUnQ7tg_UtNfSAkKdRo-rD2W93EKKB9xafPxyusFj8,6841
111
- prefect/events/utilities.py,sha256=gia_jGwxykxRTzS6FAp-gVEP9d7gH8S_hTd3-RQNJVQ,2627
111
+ prefect/events/utilities.py,sha256=zVyqNjPRtd6iJxsQfBxylerlEUrSHBk25cI_58WBJHk,2555
112
112
  prefect/events/worker.py,sha256=JAgPZjvOShWLpym-N4DeUIBQDlaAaqqG_Kkx7BcxAGY,3759
113
113
  prefect/events/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
114
  prefect/events/cli/automations.py,sha256=WIZ3-EcDibjQB5BrMEx7OZ7UfOqP8VjCI1dNh64Nmg0,11425
@@ -141,7 +141,7 @@ prefect/records/store.py,sha256=eQM1p2vZDshXZYg6SkJwL-DP3kUehL_Zgs8xa2-0DZs,224
141
141
  prefect/runner/__init__.py,sha256=7U-vAOXFkzMfRz1q8Uv6Otsvc0OrPYLLP44srwkJ_8s,89
142
142
  prefect/runner/runner.py,sha256=Lv9XeDziPgGMGFS7h4Pry4QcsXPHwuDirEJiFakq80Y,48079
143
143
  prefect/runner/server.py,sha256=2o5vhrL7Zbn-HBStWhCjqqViex5Ye9GiQ1EW9RSEzdo,10500
144
- prefect/runner/storage.py,sha256=FFHk28iF_OLw-cnXQtJIgGXUV4xecxF70mobiszP8C4,24557
144
+ prefect/runner/storage.py,sha256=OsBa4nWdFxOTiAMNLFpexBdi5K3iuxidQx4YWZwditE,24734
145
145
  prefect/runner/submit.py,sha256=RuyDr-ved9wjYYarXiehY5oJVFf_HE3XKKACNWpxpPc,8131
146
146
  prefect/runner/utils.py,sha256=wVgVa7p5uUL7tfYfDOVuq6QIGf-I8U9dfAjYBmYf6n4,3286
147
147
  prefect/runtime/__init__.py,sha256=JswiTlYRup2zXOYu8AqJ7czKtgcw9Kxo0tTbS6aWCqY,407
@@ -154,14 +154,14 @@ prefect/types/__init__.py,sha256=SAHJDtWEGidTKXQACJ38nj6fq8r57Gj0Pwo4Gy7pVWs,223
154
154
  prefect/types/entrypoint.py,sha256=2FF03-wLPgtnqR_bKJDB2BsXXINPdu8ptY9ZYEZnXg8,328
155
155
  prefect/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
156
  prefect/utilities/annotations.py,sha256=bXB43j5Zsq5gaBcJe9qnszBlnNwCTwqSTgcu2OkkRLo,2776
157
- prefect/utilities/asyncutils.py,sha256=8bOtYljRoOn-LKaMhaQWx80MM2KwUQQC0jzOuO--ZX4,20123
157
+ prefect/utilities/asyncutils.py,sha256=gVgCYMEJBy7hZCE-2Mn-mfOo0S5zViYeT_SNzOp_HwE,19889
158
158
  prefect/utilities/callables.py,sha256=agTY0XU0XWifH5SBsWLflAhNvIxOfc8Z0RRRAbCxrxk,25020
159
159
  prefect/utilities/collections.py,sha256=pPa_SZZq80cja6l99b3TV7hRQy366WnuWpOW_FnutMI,17259
160
160
  prefect/utilities/compat.py,sha256=mNQZDnzyKaOqy-OV-DnmH_dc7CNF5nQgW_EsA4xMr7g,906
161
161
  prefect/utilities/context.py,sha256=BThuUW94-IYgFYTeMIM9KMo8ShT3oiI7w5ajZHzU1j0,1377
162
162
  prefect/utilities/dispatch.py,sha256=c8G-gBo7hZlyoD7my9nO50Rzy8Retk-np5WGq9_E2AM,5856
163
163
  prefect/utilities/dockerutils.py,sha256=kRozGQ7JO6Uxl-ljWtDryzxhf96rHL78aHYDh255Em4,20324
164
- prefect/utilities/engine.py,sha256=jqE8RqixSbobaB9IxTGKIT2siv9zjT_w_99Y8dDeVVU,31518
164
+ prefect/utilities/engine.py,sha256=KNr6VVPL_EBxMAc06bAV4yHpF4lkaZKndXG6BodW3T0,31659
165
165
  prefect/utilities/filesystem.py,sha256=frAyy6qOeYa7c-jVbEUGZQEe6J1yF8I_SvUepPd59gI,4415
166
166
  prefect/utilities/hashing.py,sha256=EOwZLmoIZImuSTxAvVqInabxJ-4RpEfYeg9e2EDQF8o,1752
167
167
  prefect/utilities/importtools.py,sha256=Wo4Tj9hSf7gghP83MxW3w9FK3jkaGKPEobDYjabPqT0,19389
@@ -187,8 +187,8 @@ prefect/workers/cloud.py,sha256=BOVVY5z-vUIQ2u8LwMTXDaNys2fjOZSS5YGDwJmTQjI,230
187
187
  prefect/workers/process.py,sha256=t1f1EYRoPL5B25KbLgUX2b5q-lCCAXb2Gpf6T2M9WfY,19822
188
188
  prefect/workers/server.py,sha256=lgh2FfSuaNU7b6HPxSFm8JtKvAvHsZGkiOo4y4tW1Cw,2022
189
189
  prefect/workers/utilities.py,sha256=VfPfAlGtTuDj0-Kb8WlMgAuOfgXCdrGAnKMapPSBrwc,2483
190
- prefect_client-3.0.0rc14.dist-info/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
191
- prefect_client-3.0.0rc14.dist-info/METADATA,sha256=KGcV02xz4lmcKDK6ciIVBMGFoFNNi8Gl64l4Y3OF7kM,7474
192
- prefect_client-3.0.0rc14.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
193
- prefect_client-3.0.0rc14.dist-info/top_level.txt,sha256=MJZYJgFdbRc2woQCeB4vM6T33tr01TmkEhRcns6H_H4,8
194
- prefect_client-3.0.0rc14.dist-info/RECORD,,
190
+ prefect_client-3.0.0rc15.dist-info/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
191
+ prefect_client-3.0.0rc15.dist-info/METADATA,sha256=OgUqmtjPKFp72ME4AvM0rO-GpsM1HdekM6qBflxRhWU,7404
192
+ prefect_client-3.0.0rc15.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
193
+ prefect_client-3.0.0rc15.dist-info/top_level.txt,sha256=MJZYJgFdbRc2woQCeB4vM6T33tr01TmkEhRcns6H_H4,8
194
+ prefect_client-3.0.0rc15.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: bdist_wheel (0.44.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5