prefect-client 2.20.4__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prefect/__init__.py +74 -110
- prefect/_internal/compatibility/deprecated.py +6 -115
- prefect/_internal/compatibility/experimental.py +4 -79
- prefect/_internal/compatibility/migration.py +166 -0
- prefect/_internal/concurrency/__init__.py +2 -2
- prefect/_internal/concurrency/api.py +1 -35
- prefect/_internal/concurrency/calls.py +0 -6
- prefect/_internal/concurrency/cancellation.py +0 -3
- prefect/_internal/concurrency/event_loop.py +0 -20
- prefect/_internal/concurrency/inspection.py +3 -3
- prefect/_internal/concurrency/primitives.py +1 -0
- prefect/_internal/concurrency/services.py +23 -0
- prefect/_internal/concurrency/threads.py +35 -0
- prefect/_internal/concurrency/waiters.py +0 -28
- prefect/_internal/integrations.py +7 -0
- prefect/_internal/pydantic/__init__.py +0 -45
- prefect/_internal/pydantic/annotations/pendulum.py +2 -2
- prefect/_internal/pydantic/v1_schema.py +21 -22
- prefect/_internal/pydantic/v2_schema.py +0 -2
- prefect/_internal/pydantic/v2_validated_func.py +18 -23
- prefect/_internal/pytz.py +1 -1
- prefect/_internal/retries.py +61 -0
- prefect/_internal/schemas/bases.py +45 -177
- prefect/_internal/schemas/fields.py +1 -43
- prefect/_internal/schemas/validators.py +47 -233
- prefect/agent.py +3 -695
- prefect/artifacts.py +173 -14
- prefect/automations.py +39 -4
- prefect/blocks/abstract.py +1 -1
- prefect/blocks/core.py +405 -153
- prefect/blocks/fields.py +2 -57
- prefect/blocks/notifications.py +43 -28
- prefect/blocks/redis.py +168 -0
- prefect/blocks/system.py +67 -20
- prefect/blocks/webhook.py +2 -9
- prefect/cache_policies.py +239 -0
- prefect/client/__init__.py +4 -0
- prefect/client/base.py +33 -27
- prefect/client/cloud.py +65 -20
- prefect/client/collections.py +1 -1
- prefect/client/orchestration.py +650 -442
- prefect/client/schemas/actions.py +115 -100
- prefect/client/schemas/filters.py +46 -52
- prefect/client/schemas/objects.py +228 -178
- prefect/client/schemas/responses.py +18 -36
- prefect/client/schemas/schedules.py +55 -36
- prefect/client/schemas/sorting.py +2 -0
- prefect/client/subscriptions.py +8 -7
- prefect/client/types/flexible_schedule_list.py +11 -0
- prefect/client/utilities.py +9 -6
- prefect/concurrency/asyncio.py +60 -11
- prefect/concurrency/context.py +24 -0
- prefect/concurrency/events.py +2 -2
- prefect/concurrency/services.py +46 -16
- prefect/concurrency/sync.py +51 -7
- prefect/concurrency/v1/asyncio.py +143 -0
- prefect/concurrency/v1/context.py +27 -0
- prefect/concurrency/v1/events.py +61 -0
- prefect/concurrency/v1/services.py +116 -0
- prefect/concurrency/v1/sync.py +92 -0
- prefect/context.py +246 -149
- prefect/deployments/__init__.py +33 -18
- prefect/deployments/base.py +10 -15
- prefect/deployments/deployments.py +2 -1048
- prefect/deployments/flow_runs.py +178 -0
- prefect/deployments/runner.py +72 -173
- prefect/deployments/schedules.py +31 -25
- prefect/deployments/steps/__init__.py +0 -1
- prefect/deployments/steps/core.py +7 -0
- prefect/deployments/steps/pull.py +15 -21
- prefect/deployments/steps/utility.py +2 -1
- prefect/docker/__init__.py +20 -0
- prefect/docker/docker_image.py +82 -0
- prefect/engine.py +15 -2475
- prefect/events/actions.py +17 -23
- prefect/events/cli/automations.py +20 -7
- prefect/events/clients.py +142 -80
- prefect/events/filters.py +14 -18
- prefect/events/related.py +74 -75
- prefect/events/schemas/__init__.py +0 -5
- prefect/events/schemas/automations.py +55 -46
- prefect/events/schemas/deployment_triggers.py +7 -197
- prefect/events/schemas/events.py +46 -65
- prefect/events/schemas/labelling.py +10 -14
- prefect/events/utilities.py +4 -5
- prefect/events/worker.py +23 -8
- prefect/exceptions.py +15 -0
- prefect/filesystems.py +30 -529
- prefect/flow_engine.py +827 -0
- prefect/flow_runs.py +379 -7
- prefect/flows.py +470 -360
- prefect/futures.py +382 -331
- prefect/infrastructure/__init__.py +5 -26
- prefect/infrastructure/base.py +3 -320
- prefect/infrastructure/provisioners/__init__.py +5 -3
- prefect/infrastructure/provisioners/cloud_run.py +13 -8
- prefect/infrastructure/provisioners/container_instance.py +14 -9
- prefect/infrastructure/provisioners/ecs.py +10 -8
- prefect/infrastructure/provisioners/modal.py +8 -5
- prefect/input/__init__.py +4 -0
- prefect/input/actions.py +2 -4
- prefect/input/run_input.py +9 -9
- prefect/logging/formatters.py +2 -4
- prefect/logging/handlers.py +9 -14
- prefect/logging/loggers.py +5 -5
- prefect/main.py +72 -0
- prefect/plugins.py +2 -64
- prefect/profiles.toml +16 -2
- prefect/records/__init__.py +1 -0
- prefect/records/base.py +223 -0
- prefect/records/filesystem.py +207 -0
- prefect/records/memory.py +178 -0
- prefect/records/result_store.py +64 -0
- prefect/results.py +577 -504
- prefect/runner/runner.py +117 -47
- prefect/runner/server.py +32 -34
- prefect/runner/storage.py +3 -12
- prefect/runner/submit.py +2 -10
- prefect/runner/utils.py +2 -2
- prefect/runtime/__init__.py +1 -0
- prefect/runtime/deployment.py +1 -0
- prefect/runtime/flow_run.py +40 -5
- prefect/runtime/task_run.py +1 -0
- prefect/serializers.py +28 -39
- prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
- prefect/settings.py +209 -332
- prefect/states.py +160 -63
- prefect/task_engine.py +1478 -57
- prefect/task_runners.py +383 -287
- prefect/task_runs.py +240 -0
- prefect/task_worker.py +463 -0
- prefect/tasks.py +684 -374
- prefect/transactions.py +410 -0
- prefect/types/__init__.py +72 -86
- prefect/types/entrypoint.py +13 -0
- prefect/utilities/annotations.py +4 -3
- prefect/utilities/asyncutils.py +227 -148
- prefect/utilities/callables.py +137 -45
- prefect/utilities/collections.py +134 -86
- prefect/utilities/dispatch.py +27 -14
- prefect/utilities/dockerutils.py +11 -4
- prefect/utilities/engine.py +186 -32
- prefect/utilities/filesystem.py +4 -5
- prefect/utilities/importtools.py +26 -27
- prefect/utilities/pydantic.py +128 -38
- prefect/utilities/schema_tools/hydration.py +18 -1
- prefect/utilities/schema_tools/validation.py +30 -0
- prefect/utilities/services.py +35 -9
- prefect/utilities/templating.py +12 -2
- prefect/utilities/timeout.py +20 -5
- prefect/utilities/urls.py +195 -0
- prefect/utilities/visualization.py +1 -0
- prefect/variables.py +78 -59
- prefect/workers/__init__.py +0 -1
- prefect/workers/base.py +237 -244
- prefect/workers/block.py +5 -226
- prefect/workers/cloud.py +6 -0
- prefect/workers/process.py +265 -12
- prefect/workers/server.py +29 -11
- {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/METADATA +28 -24
- prefect_client-3.0.0.dist-info/RECORD +201 -0
- {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/WHEEL +1 -1
- prefect/_internal/pydantic/_base_model.py +0 -51
- prefect/_internal/pydantic/_compat.py +0 -82
- prefect/_internal/pydantic/_flags.py +0 -20
- prefect/_internal/pydantic/_types.py +0 -8
- prefect/_internal/pydantic/utilities/config_dict.py +0 -72
- prefect/_internal/pydantic/utilities/field_validator.py +0 -150
- prefect/_internal/pydantic/utilities/model_construct.py +0 -56
- prefect/_internal/pydantic/utilities/model_copy.py +0 -55
- prefect/_internal/pydantic/utilities/model_dump.py +0 -136
- prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
- prefect/_internal/pydantic/utilities/model_fields.py +0 -50
- prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
- prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
- prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
- prefect/_internal/pydantic/utilities/model_validate.py +0 -75
- prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
- prefect/_internal/pydantic/utilities/model_validator.py +0 -87
- prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
- prefect/_vendor/fastapi/__init__.py +0 -25
- prefect/_vendor/fastapi/applications.py +0 -946
- prefect/_vendor/fastapi/background.py +0 -3
- prefect/_vendor/fastapi/concurrency.py +0 -44
- prefect/_vendor/fastapi/datastructures.py +0 -58
- prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
- prefect/_vendor/fastapi/dependencies/models.py +0 -64
- prefect/_vendor/fastapi/dependencies/utils.py +0 -877
- prefect/_vendor/fastapi/encoders.py +0 -177
- prefect/_vendor/fastapi/exception_handlers.py +0 -40
- prefect/_vendor/fastapi/exceptions.py +0 -46
- prefect/_vendor/fastapi/logger.py +0 -3
- prefect/_vendor/fastapi/middleware/__init__.py +0 -1
- prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
- prefect/_vendor/fastapi/middleware/cors.py +0 -3
- prefect/_vendor/fastapi/middleware/gzip.py +0 -3
- prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
- prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
- prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
- prefect/_vendor/fastapi/openapi/__init__.py +0 -0
- prefect/_vendor/fastapi/openapi/constants.py +0 -2
- prefect/_vendor/fastapi/openapi/docs.py +0 -203
- prefect/_vendor/fastapi/openapi/models.py +0 -480
- prefect/_vendor/fastapi/openapi/utils.py +0 -485
- prefect/_vendor/fastapi/param_functions.py +0 -340
- prefect/_vendor/fastapi/params.py +0 -453
- prefect/_vendor/fastapi/py.typed +0 -0
- prefect/_vendor/fastapi/requests.py +0 -4
- prefect/_vendor/fastapi/responses.py +0 -40
- prefect/_vendor/fastapi/routing.py +0 -1331
- prefect/_vendor/fastapi/security/__init__.py +0 -15
- prefect/_vendor/fastapi/security/api_key.py +0 -98
- prefect/_vendor/fastapi/security/base.py +0 -6
- prefect/_vendor/fastapi/security/http.py +0 -172
- prefect/_vendor/fastapi/security/oauth2.py +0 -227
- prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
- prefect/_vendor/fastapi/security/utils.py +0 -10
- prefect/_vendor/fastapi/staticfiles.py +0 -1
- prefect/_vendor/fastapi/templating.py +0 -3
- prefect/_vendor/fastapi/testclient.py +0 -1
- prefect/_vendor/fastapi/types.py +0 -3
- prefect/_vendor/fastapi/utils.py +0 -235
- prefect/_vendor/fastapi/websockets.py +0 -7
- prefect/_vendor/starlette/__init__.py +0 -1
- prefect/_vendor/starlette/_compat.py +0 -28
- prefect/_vendor/starlette/_exception_handler.py +0 -80
- prefect/_vendor/starlette/_utils.py +0 -88
- prefect/_vendor/starlette/applications.py +0 -261
- prefect/_vendor/starlette/authentication.py +0 -159
- prefect/_vendor/starlette/background.py +0 -43
- prefect/_vendor/starlette/concurrency.py +0 -59
- prefect/_vendor/starlette/config.py +0 -151
- prefect/_vendor/starlette/convertors.py +0 -87
- prefect/_vendor/starlette/datastructures.py +0 -707
- prefect/_vendor/starlette/endpoints.py +0 -130
- prefect/_vendor/starlette/exceptions.py +0 -60
- prefect/_vendor/starlette/formparsers.py +0 -276
- prefect/_vendor/starlette/middleware/__init__.py +0 -17
- prefect/_vendor/starlette/middleware/authentication.py +0 -52
- prefect/_vendor/starlette/middleware/base.py +0 -220
- prefect/_vendor/starlette/middleware/cors.py +0 -176
- prefect/_vendor/starlette/middleware/errors.py +0 -265
- prefect/_vendor/starlette/middleware/exceptions.py +0 -74
- prefect/_vendor/starlette/middleware/gzip.py +0 -113
- prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
- prefect/_vendor/starlette/middleware/sessions.py +0 -82
- prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
- prefect/_vendor/starlette/middleware/wsgi.py +0 -147
- prefect/_vendor/starlette/py.typed +0 -0
- prefect/_vendor/starlette/requests.py +0 -328
- prefect/_vendor/starlette/responses.py +0 -347
- prefect/_vendor/starlette/routing.py +0 -933
- prefect/_vendor/starlette/schemas.py +0 -154
- prefect/_vendor/starlette/staticfiles.py +0 -248
- prefect/_vendor/starlette/status.py +0 -199
- prefect/_vendor/starlette/templating.py +0 -231
- prefect/_vendor/starlette/testclient.py +0 -804
- prefect/_vendor/starlette/types.py +0 -30
- prefect/_vendor/starlette/websockets.py +0 -193
- prefect/blocks/kubernetes.py +0 -119
- prefect/deprecated/__init__.py +0 -0
- prefect/deprecated/data_documents.py +0 -350
- prefect/deprecated/packaging/__init__.py +0 -12
- prefect/deprecated/packaging/base.py +0 -96
- prefect/deprecated/packaging/docker.py +0 -146
- prefect/deprecated/packaging/file.py +0 -92
- prefect/deprecated/packaging/orion.py +0 -80
- prefect/deprecated/packaging/serializers.py +0 -171
- prefect/events/instrument.py +0 -135
- prefect/infrastructure/container.py +0 -824
- prefect/infrastructure/kubernetes.py +0 -920
- prefect/infrastructure/process.py +0 -289
- prefect/manifests.py +0 -20
- prefect/new_flow_engine.py +0 -449
- prefect/new_task_engine.py +0 -423
- prefect/pydantic/__init__.py +0 -76
- prefect/pydantic/main.py +0 -39
- prefect/software/__init__.py +0 -2
- prefect/software/base.py +0 -50
- prefect/software/conda.py +0 -199
- prefect/software/pip.py +0 -122
- prefect/software/python.py +0 -52
- prefect/task_server.py +0 -322
- prefect_client-2.20.4.dist-info/RECORD +0 -294
- /prefect/{_internal/pydantic/utilities → client/types}/__init__.py +0 -0
- /prefect/{_vendor → concurrency/v1}/__init__.py +0 -0
- {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/LICENSE +0 -0
- {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/top_level.txt +0 -0
prefect/input/__init__.py
CHANGED
@@ -12,6 +12,8 @@ from .run_input import (
|
|
12
12
|
RunInputMetadata,
|
13
13
|
keyset_from_base_key,
|
14
14
|
keyset_from_paused_state,
|
15
|
+
receive_input,
|
16
|
+
send_input,
|
15
17
|
)
|
16
18
|
|
17
19
|
__all__ = [
|
@@ -26,4 +28,6 @@ __all__ = [
|
|
26
28
|
"keyset_from_base_key",
|
27
29
|
"keyset_from_paused_state",
|
28
30
|
"read_flow_run_input",
|
31
|
+
"receive_input",
|
32
|
+
"send_input",
|
29
33
|
]
|
prefect/input/actions.py
CHANGED
@@ -4,7 +4,6 @@ from uuid import UUID
|
|
4
4
|
import orjson
|
5
5
|
import pydantic
|
6
6
|
|
7
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
8
7
|
from prefect.client.utilities import client_injector
|
9
8
|
from prefect.context import FlowRunContext
|
10
9
|
from prefect.exceptions import PrefectHTTPStatusError
|
@@ -14,8 +13,7 @@ if TYPE_CHECKING:
|
|
14
13
|
from prefect.client.orchestration import PrefectClient
|
15
14
|
|
16
15
|
|
17
|
-
|
18
|
-
from prefect._internal.pydantic.v2_schema import is_v2_model
|
16
|
+
from prefect._internal.pydantic.v2_schema import is_v2_model
|
19
17
|
|
20
18
|
|
21
19
|
def ensure_flow_run_id(flow_run_id: Optional[UUID] = None) -> UUID:
|
@@ -41,7 +39,7 @@ async def create_flow_run_input_from_model(
|
|
41
39
|
if context is not None and context.flow_run is not None:
|
42
40
|
sender = f"prefect.flow-run.{context.flow_run.id}"
|
43
41
|
|
44
|
-
if
|
42
|
+
if is_v2_model(model_instance):
|
45
43
|
json_safe = orjson.loads(model_instance.model_dump_json())
|
46
44
|
else:
|
47
45
|
json_safe = orjson.loads(model_instance.json())
|
prefect/input/run_input.py
CHANGED
@@ -18,7 +18,8 @@ Sender flow:
|
|
18
18
|
```python
|
19
19
|
import random
|
20
20
|
from uuid import UUID
|
21
|
-
from prefect import flow
|
21
|
+
from prefect import flow
|
22
|
+
from prefect.logging import get_run_logger
|
22
23
|
from prefect.input import RunInput
|
23
24
|
|
24
25
|
class NumberData(RunInput):
|
@@ -43,7 +44,8 @@ Receiver flow:
|
|
43
44
|
```python
|
44
45
|
import random
|
45
46
|
from uuid import UUID
|
46
|
-
from prefect import flow
|
47
|
+
from prefect import flow
|
48
|
+
from prefect.logging import get_run_logger
|
47
49
|
from prefect.input import RunInput
|
48
50
|
|
49
51
|
class NumberData(RunInput):
|
@@ -77,8 +79,8 @@ from uuid import UUID, uuid4
|
|
77
79
|
|
78
80
|
import anyio
|
79
81
|
import pydantic
|
82
|
+
from pydantic import ConfigDict
|
80
83
|
|
81
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
82
84
|
from prefect.input.actions import (
|
83
85
|
create_flow_run_input,
|
84
86
|
create_flow_run_input_from_model,
|
@@ -92,8 +94,7 @@ if TYPE_CHECKING:
|
|
92
94
|
from prefect.client.schemas.objects import FlowRunInput
|
93
95
|
from prefect.states import State
|
94
96
|
|
95
|
-
|
96
|
-
from prefect._internal.pydantic.v2_schema import create_v2_schema
|
97
|
+
from prefect._internal.pydantic.v2_schema import create_v2_schema, is_v2_model
|
97
98
|
|
98
99
|
R = TypeVar("R", bound="RunInput")
|
99
100
|
T = TypeVar("T", bound="object")
|
@@ -138,13 +139,12 @@ def keyset_from_base_key(base_key: str) -> Keyset:
|
|
138
139
|
|
139
140
|
class RunInputMetadata(pydantic.BaseModel):
|
140
141
|
key: str
|
141
|
-
sender: Optional[str]
|
142
|
+
sender: Optional[str] = None
|
142
143
|
receiver: UUID
|
143
144
|
|
144
145
|
|
145
146
|
class RunInput(pydantic.BaseModel):
|
146
|
-
|
147
|
-
extra = "forbid"
|
147
|
+
model_config = ConfigDict(extra="forbid")
|
148
148
|
|
149
149
|
_description: Optional[str] = pydantic.PrivateAttr(default=None)
|
150
150
|
_metadata: RunInputMetadata = pydantic.PrivateAttr()
|
@@ -168,7 +168,7 @@ class RunInput(pydantic.BaseModel):
|
|
168
168
|
- flow_run_id (UUID, optional): the flow run ID to save the input for
|
169
169
|
"""
|
170
170
|
|
171
|
-
if
|
171
|
+
if is_v2_model(cls):
|
172
172
|
schema = create_v2_schema(cls.__name__, model_base=cls)
|
173
173
|
else:
|
174
174
|
schema = cls.schema(by_alias=True)
|
prefect/logging/formatters.py
CHANGED
@@ -48,7 +48,6 @@ class JsonFormatter(logging.Formatter):
|
|
48
48
|
|
49
49
|
self.serializer = JSONSerializer(
|
50
50
|
jsonlib="orjson",
|
51
|
-
object_encoder="pydantic.json.pydantic_encoder",
|
52
51
|
dumps_kwargs={"option": orjson.OPT_INDENT_2} if fmt == "pretty" else {},
|
53
52
|
)
|
54
53
|
|
@@ -79,8 +78,8 @@ class PrefectFormatter(logging.Formatter):
|
|
79
78
|
validate=True,
|
80
79
|
*,
|
81
80
|
defaults=None,
|
82
|
-
task_run_fmt: str = None,
|
83
|
-
flow_run_fmt: str = None,
|
81
|
+
task_run_fmt: Optional[str] = None,
|
82
|
+
flow_run_fmt: Optional[str] = None,
|
84
83
|
) -> None:
|
85
84
|
"""
|
86
85
|
Implementation of the standard Python formatter with support for multiple
|
@@ -98,7 +97,6 @@ class PrefectFormatter(logging.Formatter):
|
|
98
97
|
init_kwargs["defaults"] = defaults
|
99
98
|
style_kwargs["defaults"] = defaults
|
100
99
|
|
101
|
-
# validate added in 3.8
|
102
100
|
init_kwargs["validate"] = validate
|
103
101
|
|
104
102
|
super().__init__(format, datefmt, style, **init_kwargs)
|
prefect/logging/handlers.py
CHANGED
@@ -108,8 +108,8 @@ class APILogHandler(logging.Handler):
|
|
108
108
|
)
|
109
109
|
|
110
110
|
# Not ideal, but this method is called by the stdlib and cannot return a
|
111
|
-
# coroutine so we just schedule the drain in
|
112
|
-
from_sync.
|
111
|
+
# coroutine so we just schedule the drain in the global loop thread and continue
|
112
|
+
from_sync.call_soon_in_loop_thread(create_call(APILogWorker.drain_all))
|
113
113
|
return None
|
114
114
|
else:
|
115
115
|
# We set a timeout of 5s because we don't want to block forever if the worker
|
@@ -119,21 +119,13 @@ class APILogHandler(logging.Handler):
|
|
119
119
|
return APILogWorker.drain_all(timeout=5)
|
120
120
|
|
121
121
|
@classmethod
|
122
|
-
def aflush(cls):
|
122
|
+
async def aflush(cls):
|
123
123
|
"""
|
124
124
|
Tell the `APILogWorker` to send any currently enqueued logs and block until
|
125
125
|
completion.
|
126
|
-
|
127
|
-
If called in a synchronous context, will only block up to 5s before returning.
|
128
126
|
"""
|
129
127
|
|
130
|
-
|
131
|
-
raise RuntimeError(
|
132
|
-
"`aflush` cannot be used from a synchronous context; use `flush`"
|
133
|
-
" instead."
|
134
|
-
)
|
135
|
-
|
136
|
-
return APILogWorker.drain_all()
|
128
|
+
return await APILogWorker.drain_all()
|
137
129
|
|
138
130
|
def emit(self, record: logging.LogRecord):
|
139
131
|
"""
|
@@ -165,7 +157,10 @@ class APILogHandler(logging.Handler):
|
|
165
157
|
if log_handling_when_missing_flow == "warn":
|
166
158
|
# Warn when a logger is used outside of a run context, the stack level here
|
167
159
|
# gets us to the user logging call
|
168
|
-
warnings.warn(
|
160
|
+
warnings.warn(
|
161
|
+
f"{exc} Set PREFECT_LOGGING_TO_API_WHEN_MISSING_FLOW=ignore to suppress this warning.",
|
162
|
+
stacklevel=8,
|
163
|
+
)
|
169
164
|
return
|
170
165
|
elif log_handling_when_missing_flow == "ignore":
|
171
166
|
return
|
@@ -229,7 +224,7 @@ class APILogHandler(logging.Handler):
|
|
229
224
|
getattr(record, "created", None) or time.time()
|
230
225
|
),
|
231
226
|
message=self.format(record),
|
232
|
-
).
|
227
|
+
).model_dump(mode="json")
|
233
228
|
|
234
229
|
log_size = log["__payload_size__"] = self._get_payload_size(log)
|
235
230
|
if log_size > PREFECT_LOGGING_TO_API_MAX_LOG_SIZE.value():
|
prefect/logging/loggers.py
CHANGED
@@ -5,7 +5,7 @@ import warnings
|
|
5
5
|
from builtins import print
|
6
6
|
from contextlib import contextmanager
|
7
7
|
from functools import lru_cache
|
8
|
-
from logging import LogRecord
|
8
|
+
from logging import LoggerAdapter, LogRecord
|
9
9
|
from typing import TYPE_CHECKING, Dict, List, Optional, Union
|
10
10
|
|
11
11
|
from typing_extensions import Self
|
@@ -69,7 +69,7 @@ class PrefectLogAdapter(logging.LoggerAdapter):
|
|
69
69
|
|
70
70
|
|
71
71
|
@lru_cache()
|
72
|
-
def get_logger(name: str = None) -> logging.Logger:
|
72
|
+
def get_logger(name: Optional[str] = None) -> logging.Logger:
|
73
73
|
"""
|
74
74
|
Get a `prefect` logger. These loggers are intended for internal use within the
|
75
75
|
`prefect` package.
|
@@ -97,7 +97,7 @@ def get_logger(name: str = None) -> logging.Logger:
|
|
97
97
|
|
98
98
|
|
99
99
|
def get_run_logger(
|
100
|
-
context: "RunContext" = None, **kwargs: str
|
100
|
+
context: Optional["RunContext"] = None, **kwargs: str
|
101
101
|
) -> Union[logging.Logger, logging.LoggerAdapter]:
|
102
102
|
"""
|
103
103
|
Get a Prefect logger for the current task run or flow run.
|
@@ -115,7 +115,7 @@ def get_run_logger(
|
|
115
115
|
addition to the run metadata
|
116
116
|
|
117
117
|
Raises:
|
118
|
-
|
118
|
+
MissingContextError: If no context can be found
|
119
119
|
"""
|
120
120
|
# Check for existing contexts
|
121
121
|
task_run_context = prefect.context.TaskRunContext.get()
|
@@ -161,7 +161,7 @@ def flow_run_logger(
|
|
161
161
|
flow_run: Union["FlowRun", "ClientFlowRun"],
|
162
162
|
flow: Optional["Flow"] = None,
|
163
163
|
**kwargs: str,
|
164
|
-
):
|
164
|
+
) -> LoggerAdapter:
|
165
165
|
"""
|
166
166
|
Create a flow run logger with the run's metadata attached.
|
167
167
|
|
prefect/main.py
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Import user-facing API
|
2
|
+
from prefect.deployments import deploy
|
3
|
+
from prefect.states import State
|
4
|
+
from prefect.logging import get_run_logger
|
5
|
+
from prefect.flows import flow, Flow, serve
|
6
|
+
from prefect.transactions import Transaction
|
7
|
+
from prefect.tasks import task, Task
|
8
|
+
from prefect.context import tags
|
9
|
+
from prefect.utilities.annotations import unmapped, allow_failure
|
10
|
+
from prefect.results import BaseResult
|
11
|
+
from prefect.flow_runs import pause_flow_run, resume_flow_run, suspend_flow_run
|
12
|
+
from prefect.client.orchestration import get_client, PrefectClient
|
13
|
+
from prefect.client.cloud import get_cloud_client, CloudClient
|
14
|
+
import prefect.variables
|
15
|
+
import prefect.runtime
|
16
|
+
|
17
|
+
# Import modules that register types
|
18
|
+
import prefect.serializers
|
19
|
+
import prefect.blocks.notifications
|
20
|
+
import prefect.blocks.system
|
21
|
+
|
22
|
+
# Initialize the process-wide profile and registry at import time
|
23
|
+
import prefect.context
|
24
|
+
|
25
|
+
# Perform any forward-ref updates needed for Pydantic models
|
26
|
+
import prefect.client.schemas
|
27
|
+
|
28
|
+
prefect.context.FlowRunContext.model_rebuild(
|
29
|
+
_types_namespace={"Flow": Flow, "BaseResult": BaseResult}
|
30
|
+
)
|
31
|
+
prefect.context.TaskRunContext.model_rebuild(_types_namespace={"Task": Task})
|
32
|
+
prefect.client.schemas.State.model_rebuild(_types_namespace={"BaseResult": BaseResult})
|
33
|
+
prefect.client.schemas.StateCreate.model_rebuild(
|
34
|
+
_types_namespace={"BaseResult": BaseResult}
|
35
|
+
)
|
36
|
+
Transaction.model_rebuild()
|
37
|
+
|
38
|
+
# Configure logging
|
39
|
+
import prefect.logging.configuration
|
40
|
+
|
41
|
+
prefect.logging.configuration.setup_logging()
|
42
|
+
prefect.logging.get_logger("profiles").debug(
|
43
|
+
f"Using profile {prefect.context.get_settings_context().profile.name!r}"
|
44
|
+
)
|
45
|
+
|
46
|
+
|
47
|
+
from prefect._internal.compatibility.deprecated import (
|
48
|
+
inject_renamed_module_alias_finder,
|
49
|
+
)
|
50
|
+
|
51
|
+
inject_renamed_module_alias_finder()
|
52
|
+
|
53
|
+
|
54
|
+
# Declare API for type-checkers
|
55
|
+
__all__ = [
|
56
|
+
"allow_failure",
|
57
|
+
"flow",
|
58
|
+
"Flow",
|
59
|
+
"get_client",
|
60
|
+
"get_run_logger",
|
61
|
+
"State",
|
62
|
+
"tags",
|
63
|
+
"task",
|
64
|
+
"Task",
|
65
|
+
"Transaction",
|
66
|
+
"unmapped",
|
67
|
+
"serve",
|
68
|
+
"deploy",
|
69
|
+
"pause_flow_run",
|
70
|
+
"resume_flow_run",
|
71
|
+
"suspend_flow_run",
|
72
|
+
]
|
prefect/plugins.py
CHANGED
@@ -7,12 +7,12 @@ Currently supported entrypoints:
|
|
7
7
|
- prefect.collections: Identifies this package as a Prefect collection that
|
8
8
|
should be imported when Prefect is imported.
|
9
9
|
"""
|
10
|
-
|
10
|
+
|
11
11
|
from types import ModuleType
|
12
12
|
from typing import Any, Dict, Union
|
13
13
|
|
14
14
|
import prefect.settings
|
15
|
-
from prefect.utilities.compat import
|
15
|
+
from prefect.utilities.compat import EntryPoints, entry_points
|
16
16
|
|
17
17
|
|
18
18
|
def safe_load_entrypoints(entrypoints: EntryPoints) -> Dict[str, Union[Exception, Any]]:
|
@@ -38,68 +38,6 @@ def safe_load_entrypoints(entrypoints: EntryPoints) -> Dict[str, Union[Exception
|
|
38
38
|
return results
|
39
39
|
|
40
40
|
|
41
|
-
def load_extra_entrypoints() -> Dict[str, Union[Exception, Any]]:
|
42
|
-
# Note: Return values are only exposed for testing.
|
43
|
-
results = {}
|
44
|
-
|
45
|
-
if not prefect.settings.PREFECT_EXTRA_ENTRYPOINTS.value():
|
46
|
-
return results
|
47
|
-
|
48
|
-
values = {
|
49
|
-
value.strip()
|
50
|
-
for value in prefect.settings.PREFECT_EXTRA_ENTRYPOINTS.value().split(",")
|
51
|
-
}
|
52
|
-
|
53
|
-
entrypoints = []
|
54
|
-
for value in values:
|
55
|
-
try:
|
56
|
-
entrypoint = EntryPoint(name=None, value=value, group="prefect-extra")
|
57
|
-
except Exception as exc:
|
58
|
-
print(
|
59
|
-
(
|
60
|
-
f"Warning! Failed to parse extra entrypoint {value!r}:"
|
61
|
-
f" {type(exc).__name__}: {exc}"
|
62
|
-
),
|
63
|
-
file=sys.stderr,
|
64
|
-
)
|
65
|
-
results[value] = exc
|
66
|
-
else:
|
67
|
-
entrypoints.append(entrypoint)
|
68
|
-
|
69
|
-
for value, result in zip(
|
70
|
-
values, safe_load_entrypoints(EntryPoints(entrypoints)).values()
|
71
|
-
):
|
72
|
-
results[value] = result
|
73
|
-
|
74
|
-
if isinstance(result, Exception):
|
75
|
-
print(
|
76
|
-
(
|
77
|
-
f"Warning! Failed to load extra entrypoint {value!r}:"
|
78
|
-
f" {type(result).__name__}: {result}"
|
79
|
-
),
|
80
|
-
file=sys.stderr,
|
81
|
-
)
|
82
|
-
elif callable(result):
|
83
|
-
try:
|
84
|
-
results[value] = result()
|
85
|
-
except Exception as exc:
|
86
|
-
print(
|
87
|
-
(
|
88
|
-
f"Warning! Failed to run callable entrypoint {value!r}:"
|
89
|
-
f" {type(exc).__name__}: {exc}"
|
90
|
-
),
|
91
|
-
file=sys.stderr,
|
92
|
-
)
|
93
|
-
results[value] = exc
|
94
|
-
else:
|
95
|
-
if prefect.settings.PREFECT_DEBUG_MODE:
|
96
|
-
print(
|
97
|
-
"Loaded extra entrypoint {value!r} successfully.", file=sys.stderr
|
98
|
-
)
|
99
|
-
|
100
|
-
return results
|
101
|
-
|
102
|
-
|
103
41
|
def load_prefect_collections() -> Dict[str, ModuleType]:
|
104
42
|
"""
|
105
43
|
Load all Prefect collections that define an entrypoint in the group
|
prefect/profiles.toml
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
-
|
1
|
+
# This is a template for profile configuration for Prefect.
|
2
|
+
# You can modify these profiles or create new ones to suit your needs.
|
2
3
|
|
3
|
-
|
4
|
+
active = "ephemeral"
|
5
|
+
|
6
|
+
[profiles.ephemeral]
|
7
|
+
PREFECT_SERVER_ALLOW_EPHEMERAL_MODE = "true"
|
8
|
+
|
9
|
+
[profiles.local]
|
10
|
+
# You will need to set these values appropriately for your local development environment
|
11
|
+
PREFECT_API_URL = "http://127.0.0.1:4200/api"
|
12
|
+
|
13
|
+
[profiles.test]
|
14
|
+
PREFECT_SERVER_ALLOW_EPHEMERAL_MODE = "true"
|
15
|
+
PREFECT_API_DATABASE_CONNECTION_URL = "sqlite+aiosqlite:///:memory:"
|
16
|
+
|
17
|
+
[profiles.cloud]
|
@@ -0,0 +1 @@
|
|
1
|
+
from .base import RecordStore
|
prefect/records/base.py
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
import abc
|
2
|
+
import os
|
3
|
+
import socket
|
4
|
+
import threading
|
5
|
+
from contextlib import contextmanager
|
6
|
+
from dataclasses import dataclass
|
7
|
+
from typing import TYPE_CHECKING, Optional
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from prefect.results import BaseResult
|
11
|
+
from prefect.transactions import IsolationLevel
|
12
|
+
|
13
|
+
|
14
|
+
@dataclass
|
15
|
+
class TransactionRecord:
|
16
|
+
"""
|
17
|
+
A dataclass representation of a transaction record.
|
18
|
+
"""
|
19
|
+
|
20
|
+
key: str
|
21
|
+
result: "BaseResult"
|
22
|
+
|
23
|
+
|
24
|
+
class RecordStore(abc.ABC):
|
25
|
+
@abc.abstractmethod
|
26
|
+
def read(
|
27
|
+
self, key: str, holder: Optional[str] = None
|
28
|
+
) -> Optional[TransactionRecord]:
|
29
|
+
"""
|
30
|
+
Read the transaction record with the given key.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
key: Unique identifier for the transaction record.
|
34
|
+
holder: Unique identifier for the holder of the lock. If a lock exists on
|
35
|
+
the record being written, the read will be blocked until the lock is
|
36
|
+
released if the provided holder does not match the holder of the lock.
|
37
|
+
If not provided, a default holder based on the current host, process,
|
38
|
+
and thread will be used.
|
39
|
+
|
40
|
+
Returns:
|
41
|
+
TransactionRecord: The transaction record with the given key.
|
42
|
+
"""
|
43
|
+
...
|
44
|
+
|
45
|
+
@abc.abstractmethod
|
46
|
+
def write(self, key: str, result: "BaseResult", holder: Optional[str] = None):
|
47
|
+
"""
|
48
|
+
Write the transaction record with the given key.
|
49
|
+
|
50
|
+
Args:
|
51
|
+
key: Unique identifier for the transaction record.
|
52
|
+
record: The transaction record to write.
|
53
|
+
holder: Unique identifier for the holder of the lock. If a lock exists on
|
54
|
+
the record being written, the write will be rejected if the provided
|
55
|
+
holder does not match the holder of the lock. If not provided,
|
56
|
+
a default holder based on the current host, process, and thread will
|
57
|
+
be used.
|
58
|
+
"""
|
59
|
+
...
|
60
|
+
|
61
|
+
@abc.abstractmethod
|
62
|
+
def exists(self, key: str) -> bool:
|
63
|
+
"""
|
64
|
+
Check if the transaction record with the given key exists.
|
65
|
+
|
66
|
+
Args:
|
67
|
+
key: Unique identifier for the transaction record.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
bool: True if the record exists; False otherwise.
|
71
|
+
"""
|
72
|
+
...
|
73
|
+
|
74
|
+
@abc.abstractmethod
|
75
|
+
def supports_isolation_level(self, isolation_level: "IsolationLevel") -> bool:
|
76
|
+
"""
|
77
|
+
Check if the record store supports the given isolation level.
|
78
|
+
|
79
|
+
Args:
|
80
|
+
isolation_level: The isolation level to check.
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
bool: True if the record store supports the isolation level; False otherwise.
|
84
|
+
"""
|
85
|
+
...
|
86
|
+
|
87
|
+
def acquire_lock(
|
88
|
+
self,
|
89
|
+
key: str,
|
90
|
+
holder: Optional[str] = None,
|
91
|
+
acquire_timeout: Optional[float] = None,
|
92
|
+
hold_timeout: Optional[float] = None,
|
93
|
+
) -> bool:
|
94
|
+
"""
|
95
|
+
Acquire a lock for a transaction record with the given key. Will block other
|
96
|
+
actors from updating this transaction record until the lock is
|
97
|
+
released.
|
98
|
+
|
99
|
+
Args:
|
100
|
+
key: Unique identifier for the transaction record.
|
101
|
+
holder: Unique identifier for the holder of the lock. If not provided,
|
102
|
+
a default holder based on the current host, process, and thread will
|
103
|
+
be used.
|
104
|
+
acquire_timeout: Max number of seconds to wait for the record to become
|
105
|
+
available if it is locked while attempting to acquire a lock. Pass 0
|
106
|
+
to attempt to acquire a lock without waiting. Blocks indefinitely by
|
107
|
+
default.
|
108
|
+
hold_timeout: Max number of seconds to hold the lock for. Holds the lock
|
109
|
+
indefinitely by default.
|
110
|
+
|
111
|
+
Returns:
|
112
|
+
bool: True if the lock was successfully acquired; False otherwise.
|
113
|
+
"""
|
114
|
+
raise NotImplementedError
|
115
|
+
|
116
|
+
def release_lock(self, key: str, holder: Optional[str] = None):
|
117
|
+
"""
|
118
|
+
Releases the lock on the corresponding transaction record.
|
119
|
+
|
120
|
+
Args:
|
121
|
+
key: Unique identifier for the transaction record.
|
122
|
+
holder: Unique identifier for the holder of the lock. Must match the
|
123
|
+
holder provided when acquiring the lock.
|
124
|
+
"""
|
125
|
+
raise NotImplementedError
|
126
|
+
|
127
|
+
def is_locked(self, key: str) -> bool:
|
128
|
+
"""
|
129
|
+
Simple check to see if the corresponding record is currently locked.
|
130
|
+
|
131
|
+
Args:
|
132
|
+
key: Unique identifier for the transaction record.
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
True is the record is locked; False otherwise.
|
136
|
+
"""
|
137
|
+
raise NotImplementedError
|
138
|
+
|
139
|
+
def is_lock_holder(self, key: str, holder: Optional[str] = None) -> bool:
|
140
|
+
"""
|
141
|
+
Check if the current holder is the lock holder for the transaction record.
|
142
|
+
|
143
|
+
Args:
|
144
|
+
key: Unique identifier for the transaction record.
|
145
|
+
holder: Unique identifier for the holder of the lock. If not provided,
|
146
|
+
a default holder based on the current host, process, and thread will
|
147
|
+
be used.
|
148
|
+
|
149
|
+
Returns:
|
150
|
+
bool: True if the current holder is the lock holder; False otherwise.
|
151
|
+
"""
|
152
|
+
raise NotImplementedError
|
153
|
+
|
154
|
+
def wait_for_lock(self, key: str, timeout: Optional[float] = None) -> bool:
|
155
|
+
"""
|
156
|
+
Wait for the corresponding transaction record to become free.
|
157
|
+
|
158
|
+
Args:
|
159
|
+
key: Unique identifier for the transaction record.
|
160
|
+
timeout: Maximum time to wait. None means to wait indefinitely.
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
bool: True if the lock becomes free within the timeout; False
|
164
|
+
otherwise.
|
165
|
+
"""
|
166
|
+
...
|
167
|
+
|
168
|
+
@staticmethod
|
169
|
+
def generate_default_holder() -> str:
|
170
|
+
"""
|
171
|
+
Generate a default holder string using hostname, PID, and thread ID.
|
172
|
+
|
173
|
+
Returns:
|
174
|
+
str: A unique identifier string.
|
175
|
+
"""
|
176
|
+
hostname = socket.gethostname()
|
177
|
+
pid = os.getpid()
|
178
|
+
thread_name = threading.current_thread().name
|
179
|
+
thread_id = threading.get_ident()
|
180
|
+
return f"{hostname}:{pid}:{thread_id}:{thread_name}"
|
181
|
+
|
182
|
+
@contextmanager
|
183
|
+
def lock(
|
184
|
+
self,
|
185
|
+
key: str,
|
186
|
+
holder: Optional[str] = None,
|
187
|
+
acquire_timeout: Optional[float] = None,
|
188
|
+
hold_timeout: Optional[float] = None,
|
189
|
+
):
|
190
|
+
"""
|
191
|
+
Context manager to lock the transaction record during the execution
|
192
|
+
of the nested code block.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
key: Unique identifier for the transaction record.
|
196
|
+
holder: Unique identifier for the holder of the lock. If not provided,
|
197
|
+
a default holder based on the current host, process, and thread will
|
198
|
+
be used.
|
199
|
+
acquire_timeout: Max number of seconds to wait for the record to become
|
200
|
+
available if it is locked while attempting to acquire a lock. Pass 0
|
201
|
+
to attempt to acquire a lock without waiting. Blocks indefinitely by
|
202
|
+
default.
|
203
|
+
hold_timeout: Max number of seconds to hold the lock for. Holds the lock
|
204
|
+
indefinitely by default.
|
205
|
+
|
206
|
+
Example:
|
207
|
+
Hold a lock while during an operation:
|
208
|
+
```python
|
209
|
+
with TransactionRecord(key="my-transaction-record-key").lock():
|
210
|
+
do_stuff()
|
211
|
+
```
|
212
|
+
"""
|
213
|
+
self.acquire_lock(
|
214
|
+
key=key,
|
215
|
+
holder=holder,
|
216
|
+
acquire_timeout=acquire_timeout,
|
217
|
+
hold_timeout=hold_timeout,
|
218
|
+
)
|
219
|
+
|
220
|
+
try:
|
221
|
+
yield
|
222
|
+
finally:
|
223
|
+
self.release_lock(key=key, holder=holder)
|