prefect-client 3.9.2.dev1__py3-none-any.whl → 3.9.2.dev2__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 +3 -3
- prefect/server/api/server.py +61 -7
- {prefect_client-3.9.2.dev1.dist-info → prefect_client-3.9.2.dev2.dist-info}/METADATA +1 -1
- {prefect_client-3.9.2.dev1.dist-info → prefect_client-3.9.2.dev2.dist-info}/RECORD +6 -6
- {prefect_client-3.9.2.dev1.dist-info → prefect_client-3.9.2.dev2.dist-info}/WHEEL +0 -0
- {prefect_client-3.9.2.dev1.dist-info → prefect_client-3.9.2.dev2.dist-info}/licenses/LICENSE +0 -0
prefect/_build_info.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Generated by versioningit
|
|
2
|
-
__version__ = "3.9.2.
|
|
3
|
-
__build_date__ = "2026-11-
|
|
4
|
-
__git_commit__ = "
|
|
2
|
+
__version__ = "3.9.2.dev2"
|
|
3
|
+
__build_date__ = "2026-11-02 08:14:44.192926+00:00"
|
|
4
|
+
__git_commit__ = "da9d9dc15f647f10135a8ff79ce93c4bdb2dbf6a"
|
|
5
5
|
__dirty__ = False
|
prefect/server/api/server.py
CHANGED
|
@@ -11,7 +11,9 @@ import contextlib
|
|
|
11
11
|
import gc
|
|
12
12
|
import hmac
|
|
13
13
|
import importlib.metadata
|
|
14
|
+
import json
|
|
14
15
|
import logging
|
|
16
|
+
import math
|
|
15
17
|
import mimetypes
|
|
16
18
|
import os
|
|
17
19
|
import random
|
|
@@ -292,16 +294,34 @@ async def validation_exception_handler(
|
|
|
292
294
|
"""Provide a detailed message for request validation errors."""
|
|
293
295
|
return JSONResponse(
|
|
294
296
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
295
|
-
content=
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
297
|
+
content=_json_safe(
|
|
298
|
+
jsonable_encoder(
|
|
299
|
+
{
|
|
300
|
+
"exception_message": "Invalid request received.",
|
|
301
|
+
"exception_detail": exc.errors(),
|
|
302
|
+
"request_body": exc.body,
|
|
303
|
+
}
|
|
304
|
+
)
|
|
301
305
|
),
|
|
302
306
|
)
|
|
303
307
|
|
|
304
308
|
|
|
309
|
+
def _json_safe(value: Any) -> Any:
|
|
310
|
+
"""
|
|
311
|
+
Replace values that cannot be rendered as strict JSON, such as `NaN` or strings
|
|
312
|
+
containing unpaired surrogates, so that invalid input can be echoed back.
|
|
313
|
+
"""
|
|
314
|
+
if isinstance(value, float) and not math.isfinite(value):
|
|
315
|
+
return json.dumps(value)
|
|
316
|
+
if isinstance(value, str):
|
|
317
|
+
return value.encode("utf-8", "backslashreplace").decode("utf-8")
|
|
318
|
+
if isinstance(value, dict):
|
|
319
|
+
return {_json_safe(k): _json_safe(v) for k, v in value.items()}
|
|
320
|
+
if isinstance(value, list):
|
|
321
|
+
return [_json_safe(v) for v in value]
|
|
322
|
+
return value
|
|
323
|
+
|
|
324
|
+
|
|
305
325
|
async def integrity_exception_handler(request: Request, exc: Exception) -> JSONResponse:
|
|
306
326
|
"""Capture database integrity errors."""
|
|
307
327
|
logger.error("Encountered exception in request:", exc_info=True)
|
|
@@ -317,7 +337,20 @@ async def integrity_exception_handler(request: Request, exc: Exception) -> JSONR
|
|
|
317
337
|
)
|
|
318
338
|
|
|
319
339
|
|
|
340
|
+
def is_invalid_data_exception(exc: Exception) -> bool:
|
|
341
|
+
"""
|
|
342
|
+
Whether the database rejected a value as invalid (SQLSTATE class 22, "data
|
|
343
|
+
exception"), e.g. a NUL character or `NaN` in a PostgreSQL JSON value.
|
|
344
|
+
"""
|
|
345
|
+
orig = exc.orig if isinstance(exc, sqlalchemy.exc.DBAPIError) else exc
|
|
346
|
+
sqlstate = getattr(orig, "sqlstate", None)
|
|
347
|
+
return isinstance(sqlstate, str) and sqlstate.startswith("22")
|
|
348
|
+
|
|
349
|
+
|
|
320
350
|
def is_client_retryable_exception(exc: Exception) -> bool:
|
|
351
|
+
if is_invalid_data_exception(exc):
|
|
352
|
+
return False
|
|
353
|
+
|
|
321
354
|
if isinstance(exc, sqlalchemy.exc.OperationalError) and isinstance(
|
|
322
355
|
exc.orig, sqlite3.OperationalError
|
|
323
356
|
):
|
|
@@ -399,8 +432,29 @@ async def custom_internal_exception_handler(
|
|
|
399
432
|
"""
|
|
400
433
|
Log a detailed exception for internal server errors before returning.
|
|
401
434
|
|
|
402
|
-
Send 503 for errors clients can retry on.
|
|
435
|
+
Send 422 for values the database rejected and 503 for errors clients can retry on.
|
|
403
436
|
"""
|
|
437
|
+
if is_invalid_data_exception(exc):
|
|
438
|
+
logger.warning("Database rejected a value in request:", exc_info=True)
|
|
439
|
+
return JSONResponse(
|
|
440
|
+
content={
|
|
441
|
+
"exception_message": "Invalid request received.",
|
|
442
|
+
"exception_detail": [
|
|
443
|
+
{
|
|
444
|
+
"type": "value_error",
|
|
445
|
+
"loc": ["body"],
|
|
446
|
+
"msg": (
|
|
447
|
+
"The database rejected a value in the request. This "
|
|
448
|
+
"usually means a string contains a NUL character or a "
|
|
449
|
+
"JSON value contains NaN or Infinity. See server logs "
|
|
450
|
+
"for details."
|
|
451
|
+
),
|
|
452
|
+
}
|
|
453
|
+
],
|
|
454
|
+
},
|
|
455
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
456
|
+
)
|
|
457
|
+
|
|
404
458
|
if is_client_retryable_exception(exc):
|
|
405
459
|
if PREFECT_API_LOG_RETRYABLE_ERRORS.value():
|
|
406
460
|
logger.error("Encountered retryable exception in request:", exc_info=True)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: prefect-client
|
|
3
|
-
Version: 3.9.2.
|
|
3
|
+
Version: 3.9.2.dev2
|
|
4
4
|
Summary: Workflow orchestration and management.
|
|
5
5
|
Project-URL: Changelog, https://github.com/PrefectHQ/prefect/releases
|
|
6
6
|
Project-URL: Documentation, https://www.prefect.io/docs
|
|
@@ -2,7 +2,7 @@ prefect/.prefectignore,sha256=awSprvKT0vI8a64mEOLrMxhxqcO-b0ERQeYpA2rNKVQ,390
|
|
|
2
2
|
prefect/AGENTS.md,sha256=SRVqK72XfJPQTRQzfD6-pR04qFZJjZr7nii7W058uJg,13934
|
|
3
3
|
prefect/__init__.py,sha256=FtzUynR70uuE9WgVABo7cZkGGeNdL8Q1gJVTtmqvpyg,6772
|
|
4
4
|
prefect/__main__.py,sha256=WFjw3kaYJY6pOTA7WDOgqjsz8zUEUZHCcj3P5wyVa-g,66
|
|
5
|
-
prefect/_build_info.py,sha256=
|
|
5
|
+
prefect/_build_info.py,sha256=kTb9Bv9_n73s_06h5F7AKBbO1fjq4W4sU6D8E6pQL3M,185
|
|
6
6
|
prefect/_flow_run_suspension.py,sha256=5zTTB7ZIBHzoS0pVrhNn23-9hK51qZ3CQA6C-azluC0,4144
|
|
7
7
|
prefect/agent.py,sha256=dPvG1jDGD5HSH7aM2utwtk6RaJ9qg13XjkA0lAIgQmY,287
|
|
8
8
|
prefect/artifacts.py,sha256=ydlAad-FUepGUvTzmDkSmZLFRdMHohqVhwKnufJkeOw,23955
|
|
@@ -331,7 +331,7 @@ prefect/server/api/observed_states.py,sha256=zKe3qfNvlGwP4t6dvQqTEsg9qJHkNU1A0sB
|
|
|
331
331
|
prefect/server/api/root.py,sha256=c_av5N4MkjSfFn1fI9F9Rpn6O_haBd6mshoF8OTvNqo,1358
|
|
332
332
|
prefect/server/api/run_history.py,sha256=OR8YIP7PbviRUyehnN21KywFbuGpAt_VOFgNo2O7kcc,5428
|
|
333
333
|
prefect/server/api/saved_searches.py,sha256=tGBS8p6DjFOzwEkRhMKdxQuT900lNqA7Rr3walYuv5w,3232
|
|
334
|
-
prefect/server/api/server.py,sha256=
|
|
334
|
+
prefect/server/api/server.py,sha256=FyM-gBhp6anKsoo7K9DKng9jXB-f-FBxrXHnhP7swIo,47034
|
|
335
335
|
prefect/server/api/task_run_states.py,sha256=ZZfxj8PyVduF5RsnhVjJluDCHiIqr78WNW34NBscz2c,1651
|
|
336
336
|
prefect/server/api/task_runs.py,sha256=Y7FOYaiQnrC74YtYSFd33SEpE99Srz_CQ1-IgK_P5BM,14877
|
|
337
337
|
prefect/server/api/task_workers.py,sha256=IncrNCj2hk_QAcYt6cOWRgwPNnfwhLXEapeptYQ0Yi8,1068
|
|
@@ -452,7 +452,7 @@ prefect/workers/_worker_channel/_protocol.py,sha256=GpCNh1o3qmmqHA_UOOTge1QVC6IR
|
|
|
452
452
|
prefect/workers/_worker_channel/_state.py,sha256=eQTFZtAVDZH1vVWps3SdeY6aW3qu2wx1UKYQXK3AyuE,5369
|
|
453
453
|
prefect/workers/_worker_channel/_sync.py,sha256=G5G8_UaQYbeLebi5Mb1Z_KgGfXfyjXo5uT9la5_zwqY,14984
|
|
454
454
|
prefect/workers/_worker_channel/_transport.py,sha256=6VXxiZKIu0rqImlif14ojoAL3UGOBTmNpnlYxNggaLE,9423
|
|
455
|
-
prefect_client-3.9.2.
|
|
456
|
-
prefect_client-3.9.2.
|
|
457
|
-
prefect_client-3.9.2.
|
|
458
|
-
prefect_client-3.9.2.
|
|
455
|
+
prefect_client-3.9.2.dev2.dist-info/METADATA,sha256=gu04e149Ld2w9x-3mZSQ78tFv9P7U-Kti67ARr5kO6o,7506
|
|
456
|
+
prefect_client-3.9.2.dev2.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
457
|
+
prefect_client-3.9.2.dev2.dist-info/licenses/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
|
|
458
|
+
prefect_client-3.9.2.dev2.dist-info/RECORD,,
|
|
File without changes
|
{prefect_client-3.9.2.dev1.dist-info → prefect_client-3.9.2.dev2.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|