prefect-client 3.4.3.dev1__py3-none-any.whl → 3.4.4.dev1__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.
prefect/_build_info.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # Generated by versioningit
2
- __version__ = "3.4.3.dev1"
3
- __build_date__ = "2025-05-20 08:09:25.169022+00:00"
4
- __git_commit__ = "26c5fa05c23e2bffcdb97596e083a490352e332d"
2
+ __version__ = "3.4.4.dev1"
3
+ __build_date__ = "2025-05-24 08:07:45.528775+00:00"
4
+ __git_commit__ = "f3943ef5fc642bf19defbdb06e843c63f40f3074"
5
5
  __dirty__ = False
@@ -222,7 +222,7 @@ class Future(concurrent.futures.Future[T]):
222
222
  self._cancel_scope = None
223
223
 
224
224
 
225
- @dataclasses.dataclass
225
+ @dataclasses.dataclass(eq=False)
226
226
  class Call(Generic[T]):
227
227
  """
228
228
  A deferred function call.
@@ -236,6 +236,42 @@ class Call(Generic[T]):
236
236
  timeout: Optional[float]
237
237
  runner: Optional["Portal"] = None
238
238
 
239
+ def __eq__(self, other: object) -> bool:
240
+ """this is to avoid attempts at invalid access of args/kwargs in <3.13 stemming from the
241
+ auto-generated __eq__ method on the dataclass.
242
+
243
+ this will no longer be required in 3.13+, see https://github.com/python/cpython/issues/128294
244
+ """
245
+ if self is other:
246
+ return True
247
+ if not isinstance(other, Call):
248
+ return NotImplemented
249
+
250
+ try:
251
+ # Attempt to access args/kwargs. If any are missing on self or other,
252
+ # an AttributeError will be raised by the access attempt on one of them.
253
+ s_args, s_kwargs = self.args, self.kwargs
254
+ o_args, o_kwargs = other.args, other.kwargs
255
+ except AttributeError:
256
+ # If args/kwargs are missing on self or other (and self is not other),
257
+ # they are considered not equal. This ensures that a Call with deleted
258
+ # args/kwargs compares as different from one that still has them
259
+ return False
260
+
261
+ # If all args/kwargs were accessible on both, proceed with full field comparison.
262
+ # Note: self.future == other.future will use Future's __eq__ (default is identity).
263
+ return (
264
+ (self.future == other.future)
265
+ and (self.fn == other.fn)
266
+ and (s_args == o_args)
267
+ and (s_kwargs == o_kwargs)
268
+ and (self.context == other.context)
269
+ and (self.timeout == other.timeout)
270
+ and (self.runner == other.runner)
271
+ )
272
+
273
+ __hash__ = None # type: ignore
274
+
239
275
  @classmethod
240
276
  def new(
241
277
  cls,
@@ -18,7 +18,7 @@ from prefect.server.schemas.actions import DeploymentFlowRunCreate, StateCreate
18
18
  from prefect.server.schemas.core import WorkPool
19
19
  from prefect.server.schemas.filters import VariableFilter, VariableFilterName
20
20
  from prefect.server.schemas.responses import DeploymentResponse, OrchestrationResult
21
- from prefect.settings import PREFECT_SERVER_API_AUTH_STRING
21
+ from prefect.settings import get_current_settings
22
22
  from prefect.types import StrictVariableValue
23
23
 
24
24
  if TYPE_CHECKING:
@@ -39,18 +39,19 @@ class BaseClient:
39
39
  # will point it to the the currently running server instance
40
40
  api_app = create_app()
41
41
 
42
- # we pull the auth string from _server_ settings because this client is run on the server
43
- auth_string = PREFECT_SERVER_API_AUTH_STRING.value()
42
+ settings = get_current_settings()
44
43
 
45
- if auth_string:
46
- token = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
47
- additional_headers.setdefault("Authorization", f"Basic {token}")
44
+ # we pull the auth string from _server_ settings because this client is run on the server
45
+ if auth_string_secret := settings.server.api.auth_string:
46
+ if auth_string := auth_string_secret.get_secret_value():
47
+ token = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
48
+ additional_headers.setdefault("Authorization", f"Basic {token}")
48
49
 
49
50
  self._http_client = PrefectHttpxAsyncClient(
50
51
  transport=httpx.ASGITransport(app=api_app, raise_app_exceptions=False),
51
52
  headers={**additional_headers},
52
53
  base_url="http://prefect-in-memory/api",
53
- enable_csrf_support=False,
54
+ enable_csrf_support=settings.server.api.csrf_protection_enabled,
54
55
  raise_on_all_errors=False,
55
56
  )
56
57
 
prefect/task_engine.py CHANGED
@@ -546,9 +546,13 @@ class SyncTaskRunEngine(BaseTaskRunEngine[P, R]):
546
546
  self.retries: int = self.retries + 1
547
547
  return True
548
548
  elif self.retries >= self.task.retries:
549
+ retry_message_suffix = (
550
+ "Retries are exhausted"
551
+ if self.task.retries > 0
552
+ else "No retries configured for this task."
553
+ )
549
554
  self.logger.error(
550
- "Task run failed with exception: %r - Retries are exhausted",
551
- exc,
555
+ f"Task run failed with exception: {exc!r} - {retry_message_suffix}",
552
556
  exc_info=True,
553
557
  )
554
558
  return False
@@ -1096,9 +1100,13 @@ class AsyncTaskRunEngine(BaseTaskRunEngine[P, R]):
1096
1100
  self.retries: int = self.retries + 1
1097
1101
  return True
1098
1102
  elif self.retries >= self.task.retries:
1103
+ retry_message_suffix = (
1104
+ "Retries are exhausted"
1105
+ if self.task.retries > 0
1106
+ else "No retries configured for this task."
1107
+ )
1099
1108
  self.logger.error(
1100
- "Task run failed with exception: %r - Retries are exhausted",
1101
- exc,
1109
+ f"Task run failed with exception: {exc!r} - {retry_message_suffix}",
1102
1110
  exc_info=True,
1103
1111
  )
1104
1112
  return False
prefect/task_runners.py CHANGED
@@ -11,11 +11,8 @@ from typing import (
11
11
  TYPE_CHECKING,
12
12
  Any,
13
13
  Coroutine,
14
- Dict,
15
14
  Generic,
16
15
  Iterable,
17
- List,
18
- Optional,
19
16
  overload,
20
17
  )
21
18
 
@@ -110,7 +107,7 @@ class TaskRunner(abc.ABC, Generic[F]):
110
107
  self,
111
108
  task: "Task[P, R]",
112
109
  parameters: dict[str, Any | unmapped[Any] | allow_failure[Any]],
113
- wait_for: Optional[Iterable[PrefectFuture[R]]] = None,
110
+ wait_for: Iterable[PrefectFuture[R]] | None = None,
114
111
  ) -> PrefectFutureList[F]:
115
112
  """
116
113
  Submit multiple tasks to the task run engine.
@@ -183,7 +180,7 @@ class TaskRunner(abc.ABC, Generic[F]):
183
180
 
184
181
  map_length = list(lengths)[0]
185
182
 
186
- futures: List[PrefectFuture[Any]] = []
183
+ futures: list[PrefectFuture[Any]] = []
187
184
  for i in range(map_length):
188
185
  call_parameters: dict[str, Any] = {
189
186
  key: value[i] for key, value in iterable_parameters.items()
@@ -229,15 +226,32 @@ class TaskRunner(abc.ABC, Generic[F]):
229
226
 
230
227
 
231
228
  class ThreadPoolTaskRunner(TaskRunner[PrefectConcurrentFuture[R]]):
232
- def __init__(self, max_workers: Optional[int] = None):
229
+ """
230
+ A task runner that executes tasks in a separate thread pool.
231
+
232
+ Attributes:
233
+ max_workers: The maximum number of threads to use for executing tasks.
234
+ Defaults to `PREFECT_TASK_RUNNER_THREAD_POOL_MAX_WORKERS` or `sys.maxsize`.
235
+
236
+ Note:
237
+ This runner uses `contextvars.copy_context()` for thread-safe context propagation.
238
+ However, because contextvars are thread-local, frequent task submissions
239
+ that modify context (e.g., using `prefect.tags` in a loop) can lead to
240
+ new thread creation per task. This may cause an increase in threads and
241
+ file descriptors, potentially hitting OS limits (`OSError: Too many open files`).
242
+ If this occurs, consider minimizing context changes within looped tasks or
243
+ adjusting system limits for open file descriptors.
244
+ """
245
+
246
+ def __init__(self, max_workers: int | None = None):
233
247
  super().__init__()
234
- self._executor: Optional[ThreadPoolExecutor] = None
248
+ self._executor: ThreadPoolExecutor | None = None
235
249
  self._max_workers = (
236
250
  (PREFECT_TASK_RUNNER_THREAD_POOL_MAX_WORKERS.value() or sys.maxsize)
237
251
  if max_workers is None
238
252
  else max_workers
239
253
  )
240
- self._cancel_events: Dict[uuid.UUID, threading.Event] = {}
254
+ self._cancel_events: dict[uuid.UUID, threading.Event] = {}
241
255
 
242
256
  def duplicate(self) -> "ThreadPoolTaskRunner[R]":
243
257
  return type(self)(max_workers=self._max_workers)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prefect-client
3
- Version: 3.4.3.dev1
3
+ Version: 3.4.4.dev1
4
4
  Summary: Workflow orchestration and management.
5
5
  Project-URL: Changelog, https://github.com/PrefectHQ/prefect/releases
6
6
  Project-URL: Documentation, https://docs.prefect.io
@@ -1,7 +1,7 @@
1
1
  prefect/.prefectignore,sha256=awSprvKT0vI8a64mEOLrMxhxqcO-b0ERQeYpA2rNKVQ,390
2
2
  prefect/__init__.py,sha256=iCdcC5ZmeewikCdnPEP6YBAjPNV5dvfxpYCTpw30Hkw,3685
3
3
  prefect/__main__.py,sha256=WFjw3kaYJY6pOTA7WDOgqjsz8zUEUZHCcj3P5wyVa-g,66
4
- prefect/_build_info.py,sha256=rzOlNurTt9-Qg7Zf7Y_pzpiHVM854SAB5p9-MJ9a_pM,185
4
+ prefect/_build_info.py,sha256=UohaQdLGGqF8YTRTtCR18GfGGS00jh907nSuDMpps7o,185
5
5
  prefect/_result_records.py,sha256=S6QmsODkehGVSzbMm6ig022PYbI6gNKz671p_8kBYx4,7789
6
6
  prefect/_versioning.py,sha256=YqR5cxXrY4P6LM1Pmhd8iMo7v_G2KJpGNdsf4EvDFQ0,14132
7
7
  prefect/_waiters.py,sha256=Ia2ITaXdHzevtyWIgJoOg95lrEXQqNEOquHvw3T33UQ,9026
@@ -24,8 +24,8 @@ prefect/results.py,sha256=Amm3TQu8U_oakSn__tCogIJ5DsTj0w_kLzuENWsxK6A,36824
24
24
  prefect/schedules.py,sha256=dhq4OhImRvcmtxF7UH1m8RbwYdHT5RQsp_FrxVXfODE,7289
25
25
  prefect/serializers.py,sha256=lU9A1rGEfAfhr8nTl3rf-K7ED78QNShXOrmRBhgNk3Y,9566
26
26
  prefect/states.py,sha256=rh7l1bnIYpTXdlXt5nnpz66y9KLjBWAJrN9Eo5RwgQs,26023
27
- prefect/task_engine.py,sha256=j0rr8IyBinJmKPD-486RYWKZakhifkEE9ppPCJ9Es-U,62463
28
- prefect/task_runners.py,sha256=PozMYXXjiy5pMStifjdBTnLRTtP9uRuBa86KgafpPkQ,16243
27
+ prefect/task_engine.py,sha256=MIHEpg10imcltIRoUKjBnPKf9XuW_lh1gf5FGos_g3E,62819
28
+ prefect/task_runners.py,sha256=ptgE5wuXg_IVHM0j7d6l7ELAVg3SXSy4vggnoHRF8dA,17040
29
29
  prefect/task_runs.py,sha256=7LIzfo3fondCyEUpU05sYFN5IfpZigBDXrhG5yc-8t0,9039
30
30
  prefect/task_worker.py,sha256=RifZ3bOl6ppoYPiOAd4TQp2_GEw9eDQoW483rq1q52Q,20805
31
31
  prefect/tasks.py,sha256=s8z5k_3KUC0FXzE10-VWH17Uc36a1GKbMOn3jYGbbjk,74954
@@ -51,7 +51,7 @@ prefect/_internal/compatibility/deprecated.py,sha256=YUK1IGOgZrDh6dYRez-9IYTB1eq
51
51
  prefect/_internal/compatibility/migration.py,sha256=Z_r28B90ZQkSngXjr4I_9zA6P74_u48mtp2jYWB9zGg,6797
52
52
  prefect/_internal/concurrency/__init__.py,sha256=YlTwU9ryjPNwbJa45adLJY00t_DGCh1QrdtY9WdVFfw,2140
53
53
  prefect/_internal/concurrency/api.py,sha256=9MuQ0icQVTxwxChujn9mnv0WXRqwToysQy9GWC3sJRg,7352
54
- prefect/_internal/concurrency/calls.py,sha256=DkXNOpOrEM8IhFNE7E_ondwg1gcBeceLgoWPH3F2ExM,16596
54
+ prefect/_internal/concurrency/calls.py,sha256=e9eL7dmSairKdHg4KdRDWcM_L2CShZMtGyhp1JNxnpY,18176
55
55
  prefect/_internal/concurrency/cancellation.py,sha256=stCN22-S0f_kZPk50hCEEYzH35fBel3Nthq86FrW0MU,18675
56
56
  prefect/_internal/concurrency/event_loop.py,sha256=N6SyBV0vaSF5HD4_JM8zL7oBGd2nMuEKkeSPnBZdHw4,2136
57
57
  prefect/_internal/concurrency/inspection.py,sha256=wUWVbHi4G-BxuuYFWhTNmo5yc1C651lQrp5OMiHPU1E,3545
@@ -204,7 +204,7 @@ prefect/server/api/block_capabilities.py,sha256=7Z5kUIOs-ATKgrFI6r4es5YtuS56jnTW
204
204
  prefect/server/api/block_documents.py,sha256=zK9Tgo2FaEHDFvt9f9jLjGd4a7OEWT78IvJzHZaQQnE,5837
205
205
  prefect/server/api/block_schemas.py,sha256=9iYVsRHhswAlNxysoYa2UMeddzzltudecwwhC6hP9-Y,5497
206
206
  prefect/server/api/block_types.py,sha256=_fXzKFiWtuj4jvopQ_tHVbD0QKKngVshcR4tKM9Jqm0,8327
207
- prefect/server/api/clients.py,sha256=7Xr10JPj3FykLJ3v6Id251LgW6W-6xaWyqSU_RWcolA,8867
207
+ prefect/server/api/clients.py,sha256=IJWOatH4Bc9xOyxnMxbXEi9d1IychoMKzhXQ8_gtvZI,8995
208
208
  prefect/server/api/collections.py,sha256=RI7cjdM8RYFyAk2rgb35vqh06PWGXAamTvwThl83joY,2454
209
209
  prefect/server/api/concurrency_limits.py,sha256=E5TB2cJPIZjnxnm1pGxUJnwMDz5CS58gOGH-uGPmkes,10716
210
210
  prefect/server/api/concurrency_limits_v2.py,sha256=PGjG7W2Z65OojNTP0ezFu2z69plXo1N8paqwHlHAPj0,10183
@@ -322,7 +322,7 @@ prefect/workers/cloud.py,sha256=dPvG1jDGD5HSH7aM2utwtk6RaJ9qg13XjkA0lAIgQmY,287
322
322
  prefect/workers/process.py,sha256=Yi5D0U5AQ51wHT86GdwtImXSefe0gJf3LGq4r4z9zwM,11090
323
323
  prefect/workers/server.py,sha256=2pmVeJZiVbEK02SO6BEZaBIvHMsn6G8LzjW8BXyiTtk,1952
324
324
  prefect/workers/utilities.py,sha256=VfPfAlGtTuDj0-Kb8WlMgAuOfgXCdrGAnKMapPSBrwc,2483
325
- prefect_client-3.4.3.dev1.dist-info/METADATA,sha256=h3fL8prYMzEXZx41JfPYWC2x-QzQHZEnJ2XlETxI9Lg,7472
326
- prefect_client-3.4.3.dev1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
327
- prefect_client-3.4.3.dev1.dist-info/licenses/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
328
- prefect_client-3.4.3.dev1.dist-info/RECORD,,
325
+ prefect_client-3.4.4.dev1.dist-info/METADATA,sha256=RXF_TjvbYMjrG-NdvkrYH67JFxS2jTxSJNzXsHYYiyk,7472
326
+ prefect_client-3.4.4.dev1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
327
+ prefect_client-3.4.4.dev1.dist-info/licenses/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
328
+ prefect_client-3.4.4.dev1.dist-info/RECORD,,