prefect-client 3.1.2__py3-none-any.whl → 3.1.3__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.
@@ -1,73 +1,63 @@
1
1
  import asyncio
2
2
  import inspect
3
3
  from functools import wraps
4
- from typing import Any, Callable, Coroutine, Protocol, TypeVar, Union
4
+ from typing import Any, Callable, Coroutine, Optional, TypeVar, Union
5
5
 
6
6
  from typing_extensions import ParamSpec
7
7
 
8
+ from prefect.tasks import Task
9
+
8
10
  R = TypeVar("R")
9
11
  P = ParamSpec("P")
10
12
 
11
13
 
12
- class AsyncDispatchable(Protocol[P, R]):
13
- """Protocol for functions decorated with async_dispatch."""
14
-
15
- def __call__(
16
- self, *args: P.args, **kwargs: P.kwargs
17
- ) -> Union[R, Coroutine[Any, Any, R]]:
18
- ...
19
-
20
- aio: Callable[P, Coroutine[Any, Any, R]]
21
- sync: Callable[P, R]
22
-
23
-
24
14
  def is_in_async_context() -> bool:
25
- """Check if we're in an async context."""
15
+ """
16
+ Returns True if called from within an async context (coroutine or running event loop)
17
+ """
26
18
  try:
27
- # First check if we're in a coroutine
28
- if asyncio.current_task() is not None:
29
- return True
30
-
31
- # Check if we have a loop and it's running
32
- loop = asyncio.get_event_loop()
33
- return loop.is_running()
19
+ asyncio.get_running_loop()
20
+ return True
34
21
  except RuntimeError:
35
22
  return False
36
23
 
37
24
 
25
+ def _is_acceptable_callable(obj: Union[Callable, Task]) -> bool:
26
+ if inspect.iscoroutinefunction(obj):
27
+ return True
28
+ if isinstance(obj, Task) and inspect.iscoroutinefunction(obj.fn):
29
+ return True
30
+ return False
31
+
32
+
38
33
  def async_dispatch(
39
34
  async_impl: Callable[P, Coroutine[Any, Any, R]],
40
- ) -> Callable[[Callable[P, R]], AsyncDispatchable[P, R]]:
35
+ ) -> Callable[[Callable[P, R]], Callable[P, Union[R, Coroutine[Any, Any, R]]]]:
41
36
  """
42
- Decorator that adds async compatibility to a sync function.
43
-
44
- The decorated function will:
45
- - Return a coroutine when in an async context (detected via running event loop)
46
- - Run synchronously when in a sync context
47
- - Provide .aio for explicit async access
48
- - Provide .sync for explicit sync access
37
+ Decorator that dispatches to either sync or async implementation based on context.
49
38
 
50
39
  Args:
51
- async_impl: The async implementation to dispatch to when async execution
52
- is needed
40
+ async_impl: The async implementation to dispatch to when in async context
53
41
  """
54
- if not inspect.iscoroutinefunction(async_impl):
55
- raise TypeError(
56
- "async_impl must be an async function to dispatch in async contexts"
57
- )
58
42
 
59
- def decorator(sync_fn: Callable[P, R]) -> AsyncDispatchable[P, R]:
43
+ def decorator(
44
+ sync_fn: Callable[P, R],
45
+ ) -> Callable[P, Union[R, Coroutine[Any, Any, R]]]:
46
+ if not _is_acceptable_callable(async_impl):
47
+ raise TypeError("async_impl must be an async function")
48
+
60
49
  @wraps(sync_fn)
61
50
  def wrapper(
62
- *args: P.args, **kwargs: P.kwargs
51
+ *args: P.args,
52
+ _sync: Optional[bool] = None, # type: ignore
53
+ **kwargs: P.kwargs,
63
54
  ) -> Union[R, Coroutine[Any, Any, R]]:
64
- if is_in_async_context():
65
- return async_impl(*args, **kwargs)
66
- return sync_fn(*args, **kwargs)
55
+ should_run_sync = _sync if _sync is not None else not is_in_async_context()
56
+
57
+ if should_run_sync:
58
+ return sync_fn(*args, **kwargs)
59
+ return async_impl(*args, **kwargs)
67
60
 
68
- # Attach both async and sync implementations directly
69
- wrapper.aio = async_impl
70
- wrapper.sync = sync_fn
71
61
  return wrapper # type: ignore
72
62
 
73
63
  return decorator
prefect/_version.py CHANGED
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-11-12T13:38:45-0800",
11
+ "date": "2024-11-19T15:25:34-0600",
12
12
  "dirty": true,
13
13
  "error": null,
14
- "full-revisionid": "02b99f0a756f0395e4292952dcb2d963fc839750",
15
- "version": "3.1.2"
14
+ "full-revisionid": "39b6028cea9f2b0437546ba13cc08bb3bf6d94a4",
15
+ "version": "3.1.3"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -494,6 +494,7 @@ class OpsgenieWebhook(AbstractAppriseNotificationBlock):
494
494
  entity=self.entity,
495
495
  batch=self.batch,
496
496
  tags=self.tags,
497
+ action="new",
497
498
  ).url()
498
499
  )
499
500
  self._start_apprise_client(url)
prefect/cache_policies.py CHANGED
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional,
7
7
  from typing_extensions import Self
8
8
 
9
9
  from prefect.context import TaskRunContext
10
+ from prefect.exceptions import HashError
10
11
  from prefect.utilities.hashing import hash_objects
11
12
 
12
13
  if TYPE_CHECKING:
@@ -223,7 +224,6 @@ class TaskSource(CachePolicy):
223
224
  lines = task_ctx.task.fn.__code__.co_code
224
225
  else:
225
226
  raise
226
-
227
227
  return hash_objects(lines, raise_on_failure=True)
228
228
 
229
229
 
@@ -293,7 +293,18 @@ class Inputs(CachePolicy):
293
293
  if key not in exclude:
294
294
  hashed_inputs[key] = val
295
295
 
296
- return hash_objects(hashed_inputs, raise_on_failure=True)
296
+ try:
297
+ return hash_objects(hashed_inputs, raise_on_failure=True)
298
+ except HashError as exc:
299
+ msg = (
300
+ f"{exc}\n\n"
301
+ "This often occurs when task inputs contain objects that cannot be cached "
302
+ "like locks, file handles, or other system resources.\n\n"
303
+ "To resolve this, you can:\n"
304
+ " 1. Exclude these arguments by defining a custom `cache_key_fn`\n"
305
+ " 2. Disable caching by passing `cache_policy=NONE`\n"
306
+ )
307
+ raise ValueError(msg) from exc
297
308
 
298
309
  def __sub__(self, other: str) -> "CachePolicy":
299
310
  if not isinstance(other, str):
@@ -497,6 +497,9 @@ class FlowRunPolicy(PrefectBaseModel):
497
497
  resuming: Optional[bool] = Field(
498
498
  default=False, description="Indicates if this run is resuming from a pause."
499
499
  )
500
+ retry_type: Optional[Literal["in_process", "reschedule"]] = Field(
501
+ default=None, description="The type of retry this run is undergoing."
502
+ )
500
503
 
501
504
  @model_validator(mode="before")
502
505
  @classmethod
@@ -560,6 +563,11 @@ class FlowRun(ObjectBaseModel):
560
563
  description="A list of tags on the flow run",
561
564
  examples=[["tag-1", "tag-2"]],
562
565
  )
566
+ labels: KeyValueLabels = Field(
567
+ default_factory=dict,
568
+ description="Prefect Cloud: A dictionary of key-value labels. Values can be strings, numbers, or booleans.",
569
+ examples=[{"key": "value1", "key2": 42}],
570
+ )
563
571
  parent_task_run_id: Optional[UUID] = Field(
564
572
  default=None,
565
573
  description=(
prefect/events/filters.py CHANGED
@@ -83,17 +83,18 @@ class EventOccurredFilter(EventDataFilter):
83
83
 
84
84
  class EventNameFilter(EventDataFilter):
85
85
  prefix: Optional[List[str]] = Field(
86
- None, description="Only include events matching one of these prefixes"
86
+ default=None, description="Only include events matching one of these prefixes"
87
87
  )
88
88
  exclude_prefix: Optional[List[str]] = Field(
89
- None, description="Exclude events matching one of these prefixes"
89
+ default=None, description="Exclude events matching one of these prefixes"
90
90
  )
91
91
 
92
92
  name: Optional[List[str]] = Field(
93
- None, description="Only include events matching one of these names exactly"
93
+ default=None,
94
+ description="Only include events matching one of these names exactly",
94
95
  )
95
96
  exclude_name: Optional[List[str]] = Field(
96
- None, description="Exclude events matching one of these names exactly"
97
+ default=None, description="Exclude events matching one of these names exactly"
97
98
  )
98
99
 
99
100
  def includes(self, event: Event) -> bool:
@@ -230,17 +231,20 @@ class EventFilter(EventDataFilter):
230
231
  description="Filter criteria for when the events occurred",
231
232
  )
232
233
  event: Optional[EventNameFilter] = Field(
233
- None,
234
+ default=None,
234
235
  description="Filter criteria for the event name",
235
236
  )
236
237
  any_resource: Optional[EventAnyResourceFilter] = Field(
237
- None, description="Filter criteria for any resource involved in the event"
238
+ default=None,
239
+ description="Filter criteria for any resource involved in the event",
238
240
  )
239
241
  resource: Optional[EventResourceFilter] = Field(
240
- None, description="Filter criteria for the resource of the event"
242
+ default=None,
243
+ description="Filter criteria for the resource of the event",
241
244
  )
242
245
  related: Optional[EventRelatedFilter] = Field(
243
- None, description="Filter criteria for the related resources of the event"
246
+ default=None,
247
+ description="Filter criteria for the related resources of the event",
244
248
  )
245
249
  id: EventIDFilter = Field(
246
250
  default_factory=lambda: EventIDFilter(id=[]),
@@ -248,6 +252,6 @@ class EventFilter(EventDataFilter):
248
252
  )
249
253
 
250
254
  order: EventOrder = Field(
251
- EventOrder.DESC,
255
+ default=EventOrder.DESC,
252
256
  description="The order to return filtered events",
253
257
  )
prefect/exceptions.py CHANGED
@@ -443,3 +443,7 @@ class ProfileSettingsValidationError(PrefectException):
443
443
 
444
444
  def __init__(self, errors: List[Tuple[Any, ValidationError]]) -> None:
445
445
  self.errors = errors
446
+
447
+
448
+ class HashError(PrefectException):
449
+ """Raised when hashing objects fails"""
prefect/flow_engine.py CHANGED
@@ -22,8 +22,11 @@ from typing import (
22
22
  )
23
23
  from uuid import UUID
24
24
 
25
+ from opentelemetry import trace
26
+ from opentelemetry.trace import Tracer, get_tracer
25
27
  from typing_extensions import ParamSpec
26
28
 
29
+ import prefect
27
30
  from prefect import Task
28
31
  from prefect.client.orchestration import SyncPrefectClient, get_client
29
32
  from prefect.client.schemas import FlowRun, TaskRun
@@ -124,6 +127,10 @@ class FlowRunEngine(Generic[P, R]):
124
127
  _client: Optional[SyncPrefectClient] = None
125
128
  short_circuit: bool = False
126
129
  _flow_run_name_set: bool = False
130
+ _tracer: Tracer = field(
131
+ default_factory=lambda: get_tracer("prefect", prefect.__version__)
132
+ )
133
+ _span: Optional[trace.Span] = None
127
134
 
128
135
  def __post_init__(self):
129
136
  if self.flow is None and self.flow_run_id is None:
@@ -233,6 +240,17 @@ class FlowRunEngine(Generic[P, R]):
233
240
  self.flow_run.state = state # type: ignore
234
241
  self.flow_run.state_name = state.name # type: ignore
235
242
  self.flow_run.state_type = state.type # type: ignore
243
+
244
+ if self._span:
245
+ self._span.add_event(
246
+ state.name,
247
+ {
248
+ "prefect.state.message": state.message or "",
249
+ "prefect.state.type": state.type,
250
+ "prefect.state.name": state.name or state.type,
251
+ "prefect.state.id": str(state.id),
252
+ },
253
+ )
236
254
  return state
237
255
 
238
256
  def result(self, raise_on_failure: bool = True) -> "Union[R, State, None]":
@@ -281,6 +299,9 @@ class FlowRunEngine(Generic[P, R]):
281
299
  )
282
300
  self.set_state(terminal_state)
283
301
  self._return_value = resolved_result
302
+
303
+ self._end_span_on_success()
304
+
284
305
  return result
285
306
 
286
307
  def handle_exception(
@@ -311,6 +332,9 @@ class FlowRunEngine(Generic[P, R]):
311
332
  )
312
333
  state = self.set_state(Running())
313
334
  self._raised = exc
335
+
336
+ self._end_span_on_error(exc, state.message)
337
+
314
338
  return state
315
339
 
316
340
  def handle_timeout(self, exc: TimeoutError) -> None:
@@ -329,6 +353,8 @@ class FlowRunEngine(Generic[P, R]):
329
353
  self.set_state(state)
330
354
  self._raised = exc
331
355
 
356
+ self._end_span_on_error(exc, message)
357
+
332
358
  def handle_crash(self, exc: BaseException) -> None:
333
359
  state = run_coro_as_sync(exception_to_crashed_state(exc))
334
360
  self.logger.error(f"Crash detected! {state.message}")
@@ -336,6 +362,23 @@ class FlowRunEngine(Generic[P, R]):
336
362
  self.set_state(state, force=True)
337
363
  self._raised = exc
338
364
 
365
+ self._end_span_on_error(exc, state.message)
366
+
367
+ def _end_span_on_success(self):
368
+ if not self._span:
369
+ return
370
+ self._span.set_status(trace.Status(trace.StatusCode.OK))
371
+ self._span.end(time.time_ns())
372
+ self._span = None
373
+
374
+ def _end_span_on_error(self, exc: BaseException, description: Optional[str]):
375
+ if not self._span:
376
+ return
377
+ self._span.record_exception(exc)
378
+ self._span.set_status(trace.Status(trace.StatusCode.ERROR, description))
379
+ self._span.end(time.time_ns())
380
+ self._span = None
381
+
339
382
  def load_subflow_run(
340
383
  self,
341
384
  parent_task_run: TaskRun,
@@ -578,6 +621,18 @@ class FlowRunEngine(Generic[P, R]):
578
621
  flow_version=self.flow.version,
579
622
  empirical_policy=self.flow_run.empirical_policy,
580
623
  )
624
+
625
+ self._span = self._tracer.start_span(
626
+ name=self.flow_run.name,
627
+ attributes={
628
+ **self.flow_run.labels,
629
+ "prefect.run.type": "flow",
630
+ "prefect.run.id": str(self.flow_run.id),
631
+ "prefect.tags": self.flow_run.tags,
632
+ "prefect.flow.name": self.flow.name,
633
+ },
634
+ )
635
+
581
636
  try:
582
637
  yield self
583
638
 
@@ -632,7 +687,7 @@ class FlowRunEngine(Generic[P, R]):
632
687
 
633
688
  @contextmanager
634
689
  def start(self) -> Generator[None, None, None]:
635
- with self.initialize_run():
690
+ with self.initialize_run(), trace.use_span(self._span):
636
691
  self.begin_run()
637
692
 
638
693
  if self.state.is_running():
@@ -32,7 +32,6 @@ from prefect.settings import (
32
32
  PREFECT_LOGGING_TO_API_BATCH_SIZE,
33
33
  PREFECT_LOGGING_TO_API_MAX_LOG_SIZE,
34
34
  PREFECT_LOGGING_TO_API_WHEN_MISSING_FLOW,
35
- get_current_settings,
36
35
  )
37
36
 
38
37
 
@@ -241,10 +240,12 @@ class APILogHandler(logging.Handler):
241
240
 
242
241
  class WorkerAPILogHandler(APILogHandler):
243
242
  def emit(self, record: logging.LogRecord):
244
- if get_current_settings().experiments.worker_logging_to_api_enabled:
245
- super().emit(record)
246
- else:
243
+ # Open-source API servers do not currently support worker logs, and
244
+ # worker logs only have an associated worker ID when connected to Cloud,
245
+ # so we won't send worker logs to the API unless they have a worker ID.
246
+ if not getattr(record, "worker_id", None):
247
247
  return
248
+ super().emit(record)
248
249
 
249
250
  def prepare(self, record: logging.LogRecord) -> Dict[str, Any]:
250
251
  """
@@ -18,11 +18,6 @@ class ExperimentsSettings(PrefectBaseSettings):
18
18
  ),
19
19
  )
20
20
 
21
- worker_logging_to_api_enabled: bool = Field(
22
- default=False,
23
- description="Enables the logging of worker logs to Prefect Cloud.",
24
- )
25
-
26
21
  telemetry_enabled: bool = Field(
27
22
  default=False,
28
23
  description="Enables sending telemetry to Prefect Cloud.",
@@ -0,0 +1 @@
1
+
@@ -1,6 +1,6 @@
1
1
  import time
2
2
  from threading import Event, Lock, Thread
3
- from typing import Optional
3
+ from typing import Dict, Optional
4
4
 
5
5
  from opentelemetry.context import Context
6
6
  from opentelemetry.sdk.trace import ReadableSpan, Span, SpanProcessor
@@ -10,7 +10,7 @@ from opentelemetry.sdk.trace.export import SpanExporter
10
10
  class InFlightSpanProcessor(SpanProcessor):
11
11
  def __init__(self, span_exporter: SpanExporter):
12
12
  self.span_exporter = span_exporter
13
- self._in_flight = {}
13
+ self._in_flight: Dict[int, Span] = {}
14
14
  self._lock = Lock()
15
15
  self._stop_event = Event()
16
16
  self._export_thread = Thread(target=self._export_periodically, daemon=True)
@@ -7,7 +7,7 @@ import pathlib
7
7
  import threading
8
8
  from contextlib import contextmanager
9
9
  from pathlib import Path, PureWindowsPath
10
- from typing import Optional, Union
10
+ from typing import Optional, Union, cast
11
11
 
12
12
  import fsspec
13
13
  import pathspec
@@ -22,8 +22,8 @@ def create_default_ignore_file(path: str) -> bool:
22
22
  Creates default ignore file in the provided path if one does not already exist; returns boolean specifying
23
23
  whether a file was created.
24
24
  """
25
- path = pathlib.Path(path)
26
- ignore_file = path / ".prefectignore"
25
+ _path = pathlib.Path(path)
26
+ ignore_file = _path / ".prefectignore"
27
27
  if ignore_file.exists():
28
28
  return False
29
29
  default_file = pathlib.Path(prefect.__module_path__) / ".prefectignore"
@@ -54,12 +54,34 @@ def filter_files(
54
54
  chdir_lock = threading.Lock()
55
55
 
56
56
 
57
+ def _normalize_path(path: Union[str, Path]) -> str:
58
+ """
59
+ Normalize a path, handling UNC paths on Windows specially.
60
+ """
61
+ path = Path(path)
62
+
63
+ # Handle UNC paths on Windows differently
64
+ if os.name == "nt" and str(path).startswith("\\\\"):
65
+ # For UNC paths, use absolute() instead of resolve()
66
+ # to avoid the Windows path resolution issues
67
+ return str(path.absolute())
68
+ else:
69
+ try:
70
+ # For non-UNC paths, try resolve() first
71
+ return str(path.resolve())
72
+ except OSError:
73
+ # Fallback to absolute() if resolve() fails
74
+ return str(path.absolute())
75
+
76
+
57
77
  @contextmanager
58
78
  def tmpchdir(path: str):
59
79
  """
60
- Change current-working directories for the duration of the context
80
+ Change current-working directories for the duration of the context,
81
+ with special handling for UNC paths on Windows.
61
82
  """
62
- path = os.path.abspath(path)
83
+ path = _normalize_path(path)
84
+
63
85
  if os.path.isfile(path) or (not os.path.exists(path) and not path.endswith("/")):
64
86
  path = os.path.dirname(path)
65
87
 
@@ -67,7 +89,12 @@ def tmpchdir(path: str):
67
89
 
68
90
  with chdir_lock:
69
91
  try:
70
- os.chdir(path)
92
+ # On Windows with UNC paths, we need to handle the directory change carefully
93
+ if os.name == "nt" and path.startswith("\\\\"):
94
+ # Use os.path.abspath to handle UNC paths
95
+ os.chdir(os.path.abspath(path))
96
+ else:
97
+ os.chdir(path)
71
98
  yield path
72
99
  finally:
73
100
  os.chdir(owd)
@@ -76,7 +103,7 @@ def tmpchdir(path: str):
76
103
  def filename(path: str) -> str:
77
104
  """Extract the file name from a path with remote file system support"""
78
105
  try:
79
- of: OpenFile = fsspec.open(path)
106
+ of: OpenFile = cast(OpenFile, fsspec.open(path))
80
107
  sep = of.fs.sep
81
108
  except (ImportError, AttributeError):
82
109
  sep = "\\" if "\\" in path else "/"
@@ -98,7 +125,7 @@ def is_local_path(path: Union[str, pathlib.Path, OpenFile]):
98
125
  else:
99
126
  raise TypeError(f"Invalid path of type {type(path).__name__!r}")
100
127
 
101
- return type(of.fs) == LocalFileSystem
128
+ return isinstance(of.fs, LocalFileSystem)
102
129
 
103
130
 
104
131
  def to_display_path(
@@ -6,6 +6,7 @@ from typing import Optional, Union
6
6
 
7
7
  import cloudpickle
8
8
 
9
+ from prefect.exceptions import HashError
9
10
  from prefect.serializers import JSONSerializer
10
11
 
11
12
  if sys.version_info[:2] >= (3, 9):
@@ -53,19 +54,39 @@ def hash_objects(
53
54
  ) -> Optional[str]:
54
55
  """
55
56
  Attempt to hash objects by dumping to JSON or serializing with cloudpickle.
56
- On failure of both, `None` will be returned; to raise on failure, set
57
- `raise_on_failure=True`.
57
+
58
+ Args:
59
+ *args: Positional arguments to hash
60
+ hash_algo: Hash algorithm to use
61
+ raise_on_failure: If True, raise exceptions instead of returning None
62
+ **kwargs: Keyword arguments to hash
63
+
64
+ Returns:
65
+ A hash string or None if hashing failed
66
+
67
+ Raises:
68
+ HashError: If objects cannot be hashed and raise_on_failure is True
58
69
  """
70
+ json_error = None
71
+ pickle_error = None
72
+
59
73
  try:
60
74
  serializer = JSONSerializer(dumps_kwargs={"sort_keys": True})
61
75
  return stable_hash(serializer.dumps((args, kwargs)), hash_algo=hash_algo)
62
- except Exception:
63
- pass
76
+ except Exception as e:
77
+ json_error = str(e)
64
78
 
65
79
  try:
66
80
  return stable_hash(cloudpickle.dumps((args, kwargs)), hash_algo=hash_algo)
67
- except Exception:
68
- if raise_on_failure:
69
- raise
81
+ except Exception as e:
82
+ pickle_error = str(e)
83
+
84
+ if raise_on_failure:
85
+ msg = (
86
+ "Unable to create hash - objects could not be serialized.\n"
87
+ f" JSON error: {json_error}\n"
88
+ f" Pickle error: {pickle_error}"
89
+ )
90
+ raise HashError(msg)
70
91
 
71
92
  return None
prefect/utilities/urls.py CHANGED
@@ -3,7 +3,7 @@ import ipaddress
3
3
  import socket
4
4
  import urllib.parse
5
5
  from string import Formatter
6
- from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Union
6
+ from typing import TYPE_CHECKING, Any, Literal, Optional, Union
7
7
  from urllib.parse import urlparse
8
8
  from uuid import UUID
9
9
 
@@ -135,7 +135,7 @@ def url_for(
135
135
  obj_id: Optional[Union[str, UUID]] = None,
136
136
  url_type: URLType = "ui",
137
137
  default_base_url: Optional[str] = None,
138
- **additional_format_kwargs: Optional[Dict[str, Any]],
138
+ **additional_format_kwargs: Any,
139
139
  ) -> Optional[str]:
140
140
  """
141
141
  Returns the URL for a Prefect object.
prefect/workers/base.py CHANGED
@@ -146,26 +146,26 @@ class BaseJobConfiguration(BaseModel):
146
146
  Important: this method expects that the base_job_template was already
147
147
  validated server-side.
148
148
  """
149
- job_config: Dict[str, Any] = base_job_template["job_configuration"]
149
+ base_config: Dict[str, Any] = base_job_template["job_configuration"]
150
150
  variables_schema = base_job_template["variables"]
151
151
  variables = cls._get_base_config_defaults(
152
152
  variables_schema.get("properties", {})
153
153
  )
154
154
 
155
- # copy variable defaults for `env` to job config before they're replaced by
155
+ # copy variable defaults for `env` to base config before they're replaced by
156
156
  # deployment overrides
157
157
  if variables.get("env"):
158
- job_config["env"] = variables.get("env")
158
+ base_config["env"] = variables.get("env")
159
159
 
160
160
  variables.update(values)
161
161
 
162
162
  # deep merge `env`
163
- if isinstance(job_config.get("env"), dict) and (
164
- hardcoded_env := variables.get("env")
163
+ if isinstance(base_config.get("env"), dict) and (
164
+ deployment_env := variables.get("env")
165
165
  ):
166
- job_config["env"] = hardcoded_env | job_config.get("env")
166
+ base_config["env"] = base_config.get("env") | deployment_env
167
167
 
168
- populated_configuration = apply_values(template=job_config, values=variables)
168
+ populated_configuration = apply_values(template=base_config, values=variables)
169
169
  populated_configuration = await resolve_block_document_references(
170
170
  template=populated_configuration, client=client
171
171
  )
@@ -649,9 +649,14 @@ class BaseWorker(abc.ABC):
649
649
  for scope in self._scheduled_task_scopes:
650
650
  scope.cancel()
651
651
 
652
- await self._exit_stack.__aexit__(*exc_info)
652
+ # Emit stopped event before closing client
653
653
  if self._started_event:
654
- await self._emit_worker_stopped_event(self._started_event)
654
+ try:
655
+ await self._emit_worker_stopped_event(self._started_event)
656
+ except Exception:
657
+ self._logger.exception("Failed to emit worker stopped event")
658
+
659
+ await self._exit_stack.__aexit__(*exc_info)
655
660
  self._runs_task_group = None
656
661
  self._client = None
657
662
 
@@ -816,14 +821,14 @@ class BaseWorker(abc.ABC):
816
821
  self._logger = get_worker_logger(self)
817
822
 
818
823
  self._logger.debug(
819
- f"Worker synchronized with the Prefect API server. Remote ID: {self.backend_id}"
824
+ "Worker synchronized with the Prefect API server. "
825
+ + (f"Remote ID: {self.backend_id}" if self.backend_id else "")
820
826
  )
821
827
 
822
828
  def _should_get_worker_id(self):
823
829
  """Determines if the worker should request an ID from the API server."""
824
830
  return (
825
- get_current_settings().experiments.worker_logging_to_api_enabled
826
- and self._client
831
+ self._client
827
832
  and self._client.server_type == ServerType.CLOUD
828
833
  and self.backend_id is None
829
834
  )
@@ -881,10 +886,7 @@ class BaseWorker(abc.ABC):
881
886
  run_logger.info(
882
887
  f"Worker '{self.name}' submitting flow run '{flow_run.id}'"
883
888
  )
884
- if (
885
- get_current_settings().experiments.worker_logging_to_api_enabled
886
- and self.backend_id
887
- ):
889
+ if self.backend_id:
888
890
  try:
889
891
  worker_url = url_for(
890
892
  "worker",
@@ -971,10 +973,11 @@ class BaseWorker(abc.ABC):
971
973
 
972
974
  else:
973
975
  # If the run is not ready to submit, release the concurrency slot
974
- if self._limiter:
975
- self._limiter.release_on_behalf_of(flow_run.id)
976
+ self._release_limit_slot(flow_run.id)
976
977
 
977
978
  self._submitting_flow_run_ids.remove(flow_run.id)
979
+ else:
980
+ self._release_limit_slot(flow_run.id)
978
981
 
979
982
  async def _submit_run_and_capture_errors(
980
983
  self, flow_run: "FlowRun", task_status: Optional[anyio.abc.TaskStatus] = None
@@ -1009,8 +1012,7 @@ class BaseWorker(abc.ABC):
1009
1012
  )
1010
1013
  return exc
1011
1014
  finally:
1012
- if self._limiter:
1013
- self._limiter.release_on_behalf_of(flow_run.id)
1015
+ self._release_limit_slot(flow_run.id)
1014
1016
 
1015
1017
  if not task_status._future.done():
1016
1018
  run_logger.error(
@@ -1035,6 +1037,14 @@ class BaseWorker(abc.ABC):
1035
1037
 
1036
1038
  return result
1037
1039
 
1040
+ def _release_limit_slot(self, flow_run_id: str) -> None:
1041
+ """
1042
+ Frees up a slot taken by the given flow run id.
1043
+ """
1044
+ if self._limiter:
1045
+ self._limiter.release_on_behalf_of(flow_run_id)
1046
+ self._logger.debug("Limit slot released for flow run '%s'", flow_run_id)
1047
+
1038
1048
  def get_status(self):
1039
1049
  """
1040
1050
  Retrieves the status of the current worker including its name, current worker
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prefect-client
3
- Version: 3.1.2
3
+ Version: 3.1.3
4
4
  Summary: Workflow orchestration and management.
5
5
  Home-page: https://www.prefect.io
6
6
  Author: Prefect Technologies, Inc.
@@ -29,7 +29,7 @@ Requires-Dist: asgi-lifespan<3.0,>=1.0
29
29
  Requires-Dist: cachetools<6.0,>=5.3
30
30
  Requires-Dist: cloudpickle<4.0,>=2.0
31
31
  Requires-Dist: coolname<3.0.0,>=1.0.4
32
- Requires-Dist: croniter<5.0.0,>=1.0.12
32
+ Requires-Dist: croniter<6.0.0,>=1.0.12
33
33
  Requires-Dist: exceptiongroup>=1.0.0
34
34
  Requires-Dist: fastapi<1.0.0,>=0.111.0
35
35
  Requires-Dist: fsspec>=2022.5.0
@@ -39,6 +39,7 @@ Requires-Dist: httpcore<2.0.0,>=1.0.5
39
39
  Requires-Dist: httpx[http2]!=0.23.2,>=0.23
40
40
  Requires-Dist: jsonpatch<2.0,>=1.32
41
41
  Requires-Dist: jsonschema<5.0.0,>=4.0.0
42
+ Requires-Dist: opentelemetry-api<2.0.0,>=1.27.0
42
43
  Requires-Dist: orjson<4.0,>=3.7
43
44
  Requires-Dist: packaging<24.3,>=21.3
44
45
  Requires-Dist: pathspec>=0.8.0
@@ -1,15 +1,15 @@
1
1
  prefect/.prefectignore,sha256=awSprvKT0vI8a64mEOLrMxhxqcO-b0ERQeYpA2rNKVQ,390
2
2
  prefect/__init__.py,sha256=UZPTpdap8ECK1zLoggfeOtZGkKcf6um1-lMb-nn4o5I,3450
3
- prefect/_version.py,sha256=bglRMlWNqQBudSTba4t4FcS844kr38QYKku_fRWBhcI,496
3
+ prefect/_version.py,sha256=V4oVtbz7s0T9HhJbsnPlJc7W2E-m2PBHC2K7gFbgZOQ,496
4
4
  prefect/agent.py,sha256=BOVVY5z-vUIQ2u8LwMTXDaNys2fjOZSS5YGDwJmTQjI,230
5
5
  prefect/artifacts.py,sha256=dsxFWmdg2r9zbHM3KgKOR5YbJ29_dXUYF9kipJpbxkE,13009
6
6
  prefect/automations.py,sha256=NlQ62GPJzy-gnWQqX7c6CQJKw7p60WLGDAFcy82vtg4,5613
7
- prefect/cache_policies.py,sha256=T4RTII0qkzGq-VRoE1wGezhkdiuDtf6k7qUA46J_wbA,9196
7
+ prefect/cache_policies.py,sha256=pG6BtQw0w3f5dxlAZ-fjpILrxcTFkZH35Pa6Z4MfDtU,9762
8
8
  prefect/context.py,sha256=sNZwFecVO4-OmatU_OTNb9HoxG5rtwNIzP_NNGsmbYo,21496
9
9
  prefect/engine.py,sha256=BpmDbe6miZcTl1vRkxfCPYcWSXADLigGPCagFwucMz0,1976
10
- prefect/exceptions.py,sha256=V_nRpS2Z93PvJMoQdXbx8zepVaFb-pWanCqVi7T1ngI,11803
10
+ prefect/exceptions.py,sha256=KR8Vg7GetiBmwU5rvV5imlpg410Mv6RqSyk_gEojWAI,11884
11
11
  prefect/filesystems.py,sha256=CxwMmKY8LBUed_9IqE2jUqxVCWhXa1r2fjKgLbIC2Vg,17893
12
- prefect/flow_engine.py,sha256=BuxfnKDqYcJvmVfPlAv8yMSwkDM25SBeJVk_MGQnm8k,30076
12
+ prefect/flow_engine.py,sha256=FwmdAJd2Z2RvRhEwpTrR4xky_jzdS4dhOL7Z8MQZJ8c,31873
13
13
  prefect/flow_runs.py,sha256=EaXRIQTOnwnA0fO7_EjwafFRmS57K_CRy0Xsz3JDIhc,16070
14
14
  prefect/flows.py,sha256=PUEPpQx5pjXMVfnrPbIeAvWUdEdeaNPO4DXj7tgxGcA,90185
15
15
  prefect/futures.py,sha256=DlZvdccKtwQKuDUFrZ4zcINeO9C1chLiNOwjE5gTgCk,16356
@@ -32,7 +32,7 @@ prefect/_internal/integrations.py,sha256=U4cZMDbnilzZSKaMxvzZcSL27a1tzRMjDoTfr2u
32
32
  prefect/_internal/pytz.py,sha256=WWl9x16rKFWequGmcOGs_ljpCDPf2LDHMyZp_4D8e6c,13748
33
33
  prefect/_internal/retries.py,sha256=xtgj6oPSvYQLbyk451LR6swcRQvRVWEzCxY6GMK7qA4,2284
34
34
  prefect/_internal/compatibility/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- prefect/_internal/compatibility/async_dispatch.py,sha256=QpfHgjdmLW4PXp-sBXIqUlGL0bJnXhtLBGXi7PWR8Bo,2174
35
+ prefect/_internal/compatibility/async_dispatch.py,sha256=eTFioVEHtfPYnUxgiwJW8vBcuVA0bfOb86Rcul6i9_I,1794
36
36
  prefect/_internal/compatibility/deprecated.py,sha256=PVME2C3Oe4_8tKIGufx1W4EpGkz5IQY8gFohPVOjNcM,7533
37
37
  prefect/_internal/compatibility/migration.py,sha256=oifIj6mKwVUfrUO13ODLKOCwLON4YqaTXzhBFh8AK6E,6797
38
38
  prefect/_internal/concurrency/__init__.py,sha256=YlTwU9ryjPNwbJa45adLJY00t_DGCh1QrdtY9WdVFfw,2140
@@ -61,7 +61,7 @@ prefect/blocks/__init__.py,sha256=BUfh6gIwA6HEjRyVCAiv0he3M1zfM-oY-JrlBfeWeY8,18
61
61
  prefect/blocks/abstract.py,sha256=YLzCaf3yXv6wFCF5ZqCIHJNwH7fME1rLxC-SijARHzk,16319
62
62
  prefect/blocks/core.py,sha256=l_56oggt9uJOABHus-NCXLQ4akeY4kzyDUO37ZyosX0,52783
63
63
  prefect/blocks/fields.py,sha256=1m507VVmkpOnMF_7N-qboRjtw4_ceIuDneX3jZ3Jm54,63
64
- prefect/blocks/notifications.py,sha256=Us5xkkicFes-Xwe0h4U7kdeDBUe6qY55Ig259oGkHlY,30484
64
+ prefect/blocks/notifications.py,sha256=ufGULZCdGENKN1KYTVwVF9ZD21c_U7gE6PGKZjHOyYU,30514
65
65
  prefect/blocks/redis.py,sha256=GUKYyx2QLtyNvgf5FT_dJxbgQcOzWCja3I23J1-AXhM,5629
66
66
  prefect/blocks/system.py,sha256=OacB-LLXaNiLY49bPx7aAjmvdEdBxNoaOdzsCUcDr2c,4563
67
67
  prefect/blocks/webhook.py,sha256=F0u1WSO17Gda8qwr9gYaA84Nfc8Qkic6HhhJMYXRzug,2496
@@ -76,7 +76,7 @@ prefect/client/utilities.py,sha256=89fmza0cRMOayxgXRdO51TKb11TczJ0ByOZmcZVrt44,3
76
76
  prefect/client/schemas/__init__.py,sha256=KlyqFV-hMulMkNstBn_0ijoHoIwJZaBj6B1r07UmgvE,607
77
77
  prefect/client/schemas/actions.py,sha256=m2HJr9oAoK9vqigCHSwMGwvKPTjGNEtP0xdXgforIT0,28629
78
78
  prefect/client/schemas/filters.py,sha256=ynzD3mdvHHkI51pJ_NWgeDv8Awr7-2QtpUq7fTInEYM,36316
79
- prefect/client/schemas/objects.py,sha256=CJCMc9XrxM2EZliyvNRJdtYz8ZaI948wPFG3-BMXQdg,56753
79
+ prefect/client/schemas/objects.py,sha256=8RTtKzWOdFq8hROB77DPLCVwuKP5Jyc9gB-fOF6Qwwc,57147
80
80
  prefect/client/schemas/responses.py,sha256=tV06W8npA8oCjV9d0ZNvjro4QcbHxayb8PC4LmanXjo,15467
81
81
  prefect/client/schemas/schedules.py,sha256=8rpqjOYtknu2-1n5_WD4cOplgu93P3mCyX86B22LfL4,13070
82
82
  prefect/client/schemas/sorting.py,sha256=L-2Mx-igZPtsUoRUguTcG3nIEstMEMPD97NwPM2Ox5s,2579
@@ -109,7 +109,7 @@ prefect/docker/docker_image.py,sha256=Y84_ooCYA9NGl6FElJul9-FaW3teT-eia2SiNtZ1LG
109
109
  prefect/events/__init__.py,sha256=GtKl2bE--pJduTxelH2xy7SadlLJmmis8WR1EYixhuA,2094
110
110
  prefect/events/actions.py,sha256=A7jS8bo4zWGnrt3QfSoQs0uYC1xfKXio3IfU0XtTb5s,9129
111
111
  prefect/events/clients.py,sha256=fCR64VROlbMfVY5WL7Dy_1UroBKYrKNltll2sIiD8Ek,23028
112
- prefect/events/filters.py,sha256=IJ1TF-TCC7Wk2nJsbYW-HyAANToDQ6z1MdD63qE-lfw,8186
112
+ prefect/events/filters.py,sha256=IaJ39jGpkTocJOyrrBmnXEJEYeYZyB600Ri2apw6cxI,8294
113
113
  prefect/events/related.py,sha256=TQPYIPJI_vZlZgZgq3YpsGCmFleiZCMDtn_jMrYBJRg,6537
114
114
  prefect/events/utilities.py,sha256=ajIAiNFTN5Bz57IEq-o-i1BJdUi7P2oYH_6GyQjCKs8,2635
115
115
  prefect/events/worker.py,sha256=VEz5xgJ9KuPFNH_H08YJ2_v2lYM5ASE-Nx2Yd9DqfZ8,4126
@@ -138,7 +138,7 @@ prefect/logging/__init__.py,sha256=zx9f5_dWrR4DbcTOFBpNGOPoCZ1QcPFudr7zxb2XRpA,1
138
138
  prefect/logging/configuration.py,sha256=5kOYdd4Hi6t-wJhxEncYS9bUAMEMTRKy_i22pepjDrw,3343
139
139
  prefect/logging/filters.py,sha256=9keHLN4-cpnsWcii1qU0RITNi9-m7pOhkJ_t0MtCM4k,1117
140
140
  prefect/logging/formatters.py,sha256=3nBWgawvD48slT0zgkKeus1gIyf0OjmDKdLwMEe5mPU,3923
141
- prefect/logging/handlers.py,sha256=86uVPKimc6sBqpig6-nMSSbgXFkftvlKiRgZ7EtMqsw,11776
141
+ prefect/logging/handlers.py,sha256=ywaVcQmC8-v_B9l7Cand6kvjeFgPhfDTiqbHpQKt1vE,11943
142
142
  prefect/logging/highlighters.py,sha256=pH6TZmMaMdAkMLJB-U9NPWZIj3GUfczYCSFzCbBCq2s,1776
143
143
  prefect/logging/loggers.py,sha256=BKYjyP8N2aJPdHwpqNU5Od4uu0pKztsDQ7RPRNb4oGo,12146
144
144
  prefect/logging/logging.yml,sha256=-HoWPYLsKMt5bKRgjIqk8S7tQlAaQ93pGkwIkYtMVMo,3172
@@ -173,7 +173,7 @@ prefect/settings/models/cli.py,sha256=mHB-BHBVO9qfQcr9uHbBmU6MMDLlLUUDxjyaRz7v1l
173
173
  prefect/settings/models/client.py,sha256=Ua18wKXWrNi0Ktb6cd42kdSOQYhFnObwTHTc3QDYg2k,2985
174
174
  prefect/settings/models/cloud.py,sha256=7-WtW0rGPMOuG1O9Lwv_H_keEldXPo9YGHmoGwCXpeg,1767
175
175
  prefect/settings/models/deployments.py,sha256=ui4xqT7N-6B_gMnGnkJ8Ys0hzdfNTOtlcwzAQo2LlQI,1235
176
- prefect/settings/models/experiments.py,sha256=CXezPxuyV4pTxvQ9xroUmpEudXbDgUv-Y56A16307Wc,862
176
+ prefect/settings/models/experiments.py,sha256=toCpajFA9d2rosqshdlQBayOnyJff9zyrpRCEKAF7Bo,707
177
177
  prefect/settings/models/flows.py,sha256=IrW3cFQJnu-31cXvSihCl6naRhmZc2eFqSgqdnNLUzg,1056
178
178
  prefect/settings/models/internal.py,sha256=mJ7h3d_WHw-0FBVhIbDHPjYI041YtuReD1bZO98G1OU,612
179
179
  prefect/settings/models/logging.py,sha256=YxD8fOcWOROUrq6dH6EIadJwYL7LlLSUGWlHVLn-l3Y,4560
@@ -194,11 +194,11 @@ prefect/settings/models/server/root.py,sha256=uhryCvrk6oGAu8S3GGZNc3IaxXyd_dFnsK
194
194
  prefect/settings/models/server/services.py,sha256=xDQyRUh18mU_cTgp1Q_BwKpdeZHKLSh2o_YNNXvzsoo,16748
195
195
  prefect/settings/models/server/tasks.py,sha256=YzfRTcmiYnD_INezR_29rvO0M_YbAqT1by7kiK2KP60,2814
196
196
  prefect/settings/models/server/ui.py,sha256=6cTSC2RQsS4c2HpB1Se6qRms4RMEKSsaI40T2CTkobg,1780
197
- prefect/telemetry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
197
+ prefect/telemetry/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
198
198
  prefect/telemetry/bootstrap.py,sha256=oOdEjIHDQHANviyP2ZKpz9B4yBq832f9y1PKwAQ5-ro,987
199
199
  prefect/telemetry/instrumentation.py,sha256=S7IRYqKXaixAt-W5oxDO4CqkyXc3dy4ATgBmuindJIM,4241
200
200
  prefect/telemetry/logging.py,sha256=yn5D4D2GGRrAv0y8wlHPN7PZDmQucGjQT_YauK9M9Yo,727
201
- prefect/telemetry/processors.py,sha256=5vxjk9m-0FxqGDmVySY_u4zceZ9mwmTPiSFuCDOyGWA,2006
201
+ prefect/telemetry/processors.py,sha256=IEWBD8c_O3lx54TbIsBOF8kneIMcT27bcwh3O0VY7HI,2029
202
202
  prefect/types/__init__.py,sha256=oabzKSvuT7tKBX6OiBev40wUtN1JstJT2L7ocpEUZ14,3640
203
203
  prefect/types/entrypoint.py,sha256=2FF03-wLPgtnqR_bKJDB2BsXXINPdu8ptY9ZYEZnXg8,328
204
204
  prefect/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -211,8 +211,8 @@ prefect/utilities/context.py,sha256=BThuUW94-IYgFYTeMIM9KMo8ShT3oiI7w5ajZHzU1j0,
211
211
  prefect/utilities/dispatch.py,sha256=EthEmyRwv-4W8z2BJclrsOQHJ_pJoZYL0t2cyYPEa-E,6098
212
212
  prefect/utilities/dockerutils.py,sha256=zjqeyE4gK8r0n5l3b2XK2AKviQ2F-pOd1LE2O4qfJt0,20372
213
213
  prefect/utilities/engine.py,sha256=pi-TQEpoJ98u2LNYh3ZpNoiN9VSlGRJV558Hjg2eFxY,32433
214
- prefect/utilities/filesystem.py,sha256=frAyy6qOeYa7c-jVbEUGZQEe6J1yF8I_SvUepPd59gI,4415
215
- prefect/utilities/hashing.py,sha256=SK18PDwJQjn3_qwNwwnz6Wuz1o8rR6Bja-sEuSfszxE,1879
214
+ prefect/utilities/filesystem.py,sha256=FH5SRDeLei5_nouYmYkr44GdCJy7p9rIV-VyhW71ziE,5420
215
+ prefect/utilities/hashing.py,sha256=IrcILlSvLz1hFtOFtIelPtkcyZ7qnaARYlrGFv3eVxs,2485
216
216
  prefect/utilities/importtools.py,sha256=aO-xhf2h2KzsLGvSKwRAZLB4ITeW9rsV0Ys-gwq3i7o,19426
217
217
  prefect/utilities/math.py,sha256=wLwcKVidpNeWQi1TUIWWLHGjlz9UgboX9FUGhx_CQzo,2821
218
218
  prefect/utilities/names.py,sha256=x-stHcF7_tebJPvB1dz-5FvdXJXNBTg2kFZXSnIBBmk,1657
@@ -224,20 +224,20 @@ prefect/utilities/slugify.py,sha256=57Vb14t13F3zm1P65KAu8nVeAz0iJCd1Qc5eMG-R5y8,
224
224
  prefect/utilities/templating.py,sha256=nAiOGMMHGbIDFkGYy-g-dzcbY311WfycdgAhsM3cLpY,13298
225
225
  prefect/utilities/text.py,sha256=JRs6WNUn07i5oRP_jyTUYD6I0hdVwyMI0JmJc8f9gFw,731
226
226
  prefect/utilities/timeout.py,sha256=BRDIOWnqcw3B7X9tIk83Y3n9nQrJzZgduDQ63z-ns8w,1286
227
- prefect/utilities/urls.py,sha256=Wj7Q2vSSc11lX6FC0Wd295uTHDArDEa3rHJ967JJfPs,8919
227
+ prefect/utilities/urls.py,sha256=NQqtifJRoewrXXjYmxC7YAkaMb1nE00evwjxO40Gmoc,8892
228
228
  prefect/utilities/visualization.py,sha256=Lum4IvLQ0nHsdLt6GGzS3Wwo-828u1rmOKc5mmWu994,6502
229
229
  prefect/utilities/schema_tools/__init__.py,sha256=KsFsTEHQqgp89TkDpjggkgBBywoHQPxbx-m6YQhiNEI,322
230
230
  prefect/utilities/schema_tools/hydration.py,sha256=k12qVCdLLrK-mNo1hPCdhxM5f_N14Nj0vJdtiWYWffk,8858
231
231
  prefect/utilities/schema_tools/validation.py,sha256=2GCjxwApTFwzey40ul9OkcAXrU3r-kWK__9ucMo0qbk,9744
232
232
  prefect/workers/__init__.py,sha256=8dP8SLZbWYyC_l9DRTQSE3dEbDgns5DZDhxkp_NfsbQ,35
233
- prefect/workers/base.py,sha256=bgFZWymeu4RMUDH97R7tMPmrJSoLKVPZCoGAPkjHfVk,48898
233
+ prefect/workers/base.py,sha256=7Gb19vDG1cFsyrfsvZIR1h-OvX5T3RFrSS0Vj7uO5JU,49209
234
234
  prefect/workers/block.py,sha256=BOVVY5z-vUIQ2u8LwMTXDaNys2fjOZSS5YGDwJmTQjI,230
235
235
  prefect/workers/cloud.py,sha256=BOVVY5z-vUIQ2u8LwMTXDaNys2fjOZSS5YGDwJmTQjI,230
236
236
  prefect/workers/process.py,sha256=tcJ3fbiraLCfpVGpv8dOHwMSfVzeD_kyguUOvPuIz6I,19796
237
237
  prefect/workers/server.py,sha256=lgh2FfSuaNU7b6HPxSFm8JtKvAvHsZGkiOo4y4tW1Cw,2022
238
238
  prefect/workers/utilities.py,sha256=VfPfAlGtTuDj0-Kb8WlMgAuOfgXCdrGAnKMapPSBrwc,2483
239
- prefect_client-3.1.2.dist-info/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
240
- prefect_client-3.1.2.dist-info/METADATA,sha256=zs_vo1177_sGYQJnaNXeYU34A0hvA6hHMWzOLIbJ7CE,7338
241
- prefect_client-3.1.2.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
242
- prefect_client-3.1.2.dist-info/top_level.txt,sha256=MJZYJgFdbRc2woQCeB4vM6T33tr01TmkEhRcns6H_H4,8
243
- prefect_client-3.1.2.dist-info/RECORD,,
239
+ prefect_client-3.1.3.dist-info/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
240
+ prefect_client-3.1.3.dist-info/METADATA,sha256=PdG3F-fwco9gK2XcOTh-Os4oyp_5HzQSR5tx_BMPXiM,7386
241
+ prefect_client-3.1.3.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
242
+ prefect_client-3.1.3.dist-info/top_level.txt,sha256=MJZYJgFdbRc2woQCeB4vM6T33tr01TmkEhRcns6H_H4,8
243
+ prefect_client-3.1.3.dist-info/RECORD,,