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/blocks/fields.py
CHANGED
@@ -1,58 +1,3 @@
|
|
1
|
-
from
|
1
|
+
from prefect.types import SecretDict
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
if HAS_PYDANTIC_V2:
|
6
|
-
from pydantic.v1 import SecretField
|
7
|
-
from pydantic.v1.utils import update_not_none
|
8
|
-
from pydantic.v1.validators import dict_validator
|
9
|
-
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
from pydantic.v1.typing import CallableGenerator
|
12
|
-
|
13
|
-
else:
|
14
|
-
from pydantic import SecretField
|
15
|
-
from pydantic.utils import update_not_none
|
16
|
-
from pydantic.validators import dict_validator
|
17
|
-
|
18
|
-
if TYPE_CHECKING:
|
19
|
-
from pydantic.typing import CallableGenerator
|
20
|
-
|
21
|
-
|
22
|
-
class SecretDict(SecretField):
|
23
|
-
@classmethod
|
24
|
-
def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None:
|
25
|
-
update_not_none(
|
26
|
-
field_schema,
|
27
|
-
type="object",
|
28
|
-
)
|
29
|
-
|
30
|
-
@classmethod
|
31
|
-
def __get_validators__(cls) -> "CallableGenerator":
|
32
|
-
yield cls.validate
|
33
|
-
|
34
|
-
@classmethod
|
35
|
-
def validate(cls, value: Any) -> "SecretDict":
|
36
|
-
if isinstance(value, cls):
|
37
|
-
return value
|
38
|
-
value = dict_validator(value)
|
39
|
-
return cls(value)
|
40
|
-
|
41
|
-
def __init__(self, value: Dict[str, Any]):
|
42
|
-
self._secret_value = value
|
43
|
-
|
44
|
-
def __str__(self) -> str:
|
45
|
-
return (
|
46
|
-
str({key: "**********" for key in self.get_secret_value().keys()})
|
47
|
-
if self.get_secret_value()
|
48
|
-
else ""
|
49
|
-
)
|
50
|
-
|
51
|
-
def __repr__(self) -> str:
|
52
|
-
return f"SecretDict('{self}')"
|
53
|
-
|
54
|
-
def get_secret_value(self) -> Dict[str, Any]:
|
55
|
-
return self._secret_value
|
56
|
-
|
57
|
-
def dict(self) -> Dict:
|
58
|
-
return {key: "**********" for key in self.get_secret_value().keys()}
|
3
|
+
__all__ = ["SecretDict"]
|
prefect/blocks/notifications.py
CHANGED
@@ -2,19 +2,12 @@ import logging
|
|
2
2
|
from abc import ABC
|
3
3
|
from typing import Dict, List, Optional
|
4
4
|
|
5
|
-
from
|
6
|
-
from prefect.logging import LogEavesdropper
|
7
|
-
|
8
|
-
if HAS_PYDANTIC_V2:
|
9
|
-
from pydantic.v1 import AnyHttpUrl, Field, SecretStr
|
10
|
-
else:
|
11
|
-
from pydantic import AnyHttpUrl, Field, SecretStr
|
12
|
-
|
5
|
+
from pydantic import AnyHttpUrl, Field, SecretStr
|
13
6
|
from typing_extensions import Literal
|
14
7
|
|
15
8
|
from prefect.blocks.abstract import NotificationBlock, NotificationError
|
16
|
-
from prefect.
|
17
|
-
from prefect.
|
9
|
+
from prefect.logging import LogEavesdropper
|
10
|
+
from prefect.types import SecretDict
|
18
11
|
from prefect.utilities.asyncutils import sync_compatible
|
19
12
|
from prefect.utilities.templating import apply_values, find_placeholders
|
20
13
|
|
@@ -62,7 +55,6 @@ class AbstractAppriseNotificationBlock(NotificationBlock, ABC):
|
|
62
55
|
self._start_apprise_client(self.url)
|
63
56
|
|
64
57
|
@sync_compatible
|
65
|
-
@instrument_instance_method_call
|
66
58
|
async def notify(
|
67
59
|
self,
|
68
60
|
body: str,
|
@@ -137,11 +129,11 @@ class MicrosoftTeamsWebhook(AppriseNotificationBlock):
|
|
137
129
|
_documentation_url = "https://docs.prefect.io/api-ref/prefect/blocks/notifications/#prefect.blocks.notifications.MicrosoftTeamsWebhook"
|
138
130
|
|
139
131
|
url: SecretStr = Field(
|
140
|
-
|
132
|
+
default=...,
|
141
133
|
title="Webhook URL",
|
142
134
|
description="The Microsoft Power Automate (Workflows) URL used to send notifications to Teams.",
|
143
135
|
examples=[
|
144
|
-
"https://prod-NO.LOCATION.logic.azure.com:443/workflows/WFID/triggers/manual/paths/invoke?sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=SIGNATURE"
|
136
|
+
"https://prod-NO.LOCATION.logic.azure.com:443/workflows/WFID/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=SIGNATURE"
|
145
137
|
],
|
146
138
|
)
|
147
139
|
|
@@ -164,12 +156,7 @@ class MicrosoftTeamsWebhook(AppriseNotificationBlock):
|
|
164
156
|
):
|
165
157
|
raise ValueError("Invalid Microsoft Teams Workflow URL provided.")
|
166
158
|
|
167
|
-
parsed_url.
|
168
|
-
{
|
169
|
-
"include_image": self.include_image,
|
170
|
-
"wrap": self.wrap,
|
171
|
-
}
|
172
|
-
)
|
159
|
+
parsed_url |= {"include_image": self.include_image, "wrap": self.wrap}
|
173
160
|
|
174
161
|
self._start_apprise_client(SecretStr(NotifyWorkflows(**parsed_url).url()))
|
175
162
|
|
@@ -263,7 +250,12 @@ class PagerDutyWebHook(AbstractAppriseNotificationBlock):
|
|
263
250
|
)
|
264
251
|
|
265
252
|
def block_initialization(self) -> None:
|
266
|
-
|
253
|
+
try:
|
254
|
+
# Try importing for apprise>=1.18.0
|
255
|
+
from apprise.plugins.pagerduty import NotifyPagerDuty
|
256
|
+
except ImportError:
|
257
|
+
# Fallback for versions apprise<1.18.0
|
258
|
+
from apprise.plugins.NotifyPagerDuty import NotifyPagerDuty
|
267
259
|
|
268
260
|
url = SecretStr(
|
269
261
|
NotifyPagerDuty(
|
@@ -331,8 +323,12 @@ class TwilioSMS(AbstractAppriseNotificationBlock):
|
|
331
323
|
)
|
332
324
|
|
333
325
|
def block_initialization(self) -> None:
|
334
|
-
|
335
|
-
|
326
|
+
try:
|
327
|
+
# Try importing for apprise>=1.18.0
|
328
|
+
from apprise.plugins.twilio import NotifyTwilio
|
329
|
+
except ImportError:
|
330
|
+
# Fallback for versions apprise<1.18.0
|
331
|
+
from apprise.plugins.NotifyTwilio import NotifyTwilio
|
336
332
|
url = SecretStr(
|
337
333
|
NotifyTwilio(
|
338
334
|
account_sid=self.account_sid,
|
@@ -406,7 +402,7 @@ class OpsgenieWebhook(AbstractAppriseNotificationBlock):
|
|
406
402
|
examples=['["tag1", "tag2"]'],
|
407
403
|
)
|
408
404
|
|
409
|
-
priority: Optional[
|
405
|
+
priority: Optional[int] = Field(
|
410
406
|
default=3,
|
411
407
|
description=(
|
412
408
|
"The priority to associate with the message. It is on a scale between 1"
|
@@ -429,7 +425,12 @@ class OpsgenieWebhook(AbstractAppriseNotificationBlock):
|
|
429
425
|
)
|
430
426
|
|
431
427
|
def block_initialization(self) -> None:
|
432
|
-
|
428
|
+
try:
|
429
|
+
# Try importing for apprise>=1.18.0
|
430
|
+
from apprise.plugins.opsgenie import NotifyOpsgenie
|
431
|
+
except ImportError:
|
432
|
+
# Fallback for versions apprise<1.18.0
|
433
|
+
from apprise.plugins.NotifyOpsgenie import NotifyOpsgenie
|
433
434
|
|
434
435
|
targets = []
|
435
436
|
if self.target_user:
|
@@ -517,7 +518,12 @@ class MattermostWebhook(AbstractAppriseNotificationBlock):
|
|
517
518
|
)
|
518
519
|
|
519
520
|
def block_initialization(self) -> None:
|
520
|
-
|
521
|
+
try:
|
522
|
+
# Try importing for apprise>=1.18.0
|
523
|
+
from apprise.plugins.mattermost import NotifyMattermost
|
524
|
+
except ImportError:
|
525
|
+
# Fallback for versions apprise<1.18.0
|
526
|
+
from apprise.plugins.NotifyMattermost import NotifyMattermost
|
521
527
|
|
522
528
|
url = SecretStr(
|
523
529
|
NotifyMattermost(
|
@@ -610,7 +616,12 @@ class DiscordWebhook(AbstractAppriseNotificationBlock):
|
|
610
616
|
)
|
611
617
|
|
612
618
|
def block_initialization(self) -> None:
|
613
|
-
|
619
|
+
try:
|
620
|
+
# Try importing for apprise>=1.18.0
|
621
|
+
from apprise.plugins.discord import NotifyDiscord
|
622
|
+
except ImportError:
|
623
|
+
# Fallback for versions apprise<1.18.0
|
624
|
+
from apprise.plugins.NotifyDiscord import NotifyDiscord
|
614
625
|
|
615
626
|
url = SecretStr(
|
616
627
|
NotifyDiscord(
|
@@ -745,7 +756,6 @@ class CustomWebhookNotificationBlock(NotificationBlock):
|
|
745
756
|
raise KeyError(f"{name}/{placeholder}")
|
746
757
|
|
747
758
|
@sync_compatible
|
748
|
-
@instrument_instance_method_call
|
749
759
|
async def notify(self, body: str, subject: Optional[str] = None):
|
750
760
|
import httpx
|
751
761
|
|
@@ -801,7 +811,12 @@ class SendgridEmail(AbstractAppriseNotificationBlock):
|
|
801
811
|
)
|
802
812
|
|
803
813
|
def block_initialization(self) -> None:
|
804
|
-
|
814
|
+
try:
|
815
|
+
# Try importing for apprise>=1.18.0
|
816
|
+
from apprise.plugins.sendgrid import NotifySendGrid
|
817
|
+
except ImportError:
|
818
|
+
# Fallback for versions apprise<1.18.0
|
819
|
+
from apprise.plugins.NotifySendGrid import NotifySendGrid
|
805
820
|
|
806
821
|
url = SecretStr(
|
807
822
|
NotifySendGrid(
|
prefect/blocks/redis.py
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
from contextlib import asynccontextmanager
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import AsyncGenerator, Optional, Union
|
4
|
+
|
5
|
+
try:
|
6
|
+
import redis.asyncio as redis
|
7
|
+
except ImportError:
|
8
|
+
raise ImportError(
|
9
|
+
"`redis-py` must be installed to use the `RedisStorageContainer` block. "
|
10
|
+
"You can install it with `pip install redis>=5.0.1"
|
11
|
+
)
|
12
|
+
|
13
|
+
from pydantic import Field
|
14
|
+
from pydantic.types import SecretStr
|
15
|
+
from typing_extensions import Self
|
16
|
+
|
17
|
+
from prefect.filesystems import WritableFileSystem
|
18
|
+
from prefect.utilities.asyncutils import sync_compatible
|
19
|
+
|
20
|
+
|
21
|
+
class RedisStorageContainer(WritableFileSystem):
|
22
|
+
"""
|
23
|
+
Block used to interact with Redis as a filesystem
|
24
|
+
|
25
|
+
Attributes:
|
26
|
+
host (str): The value to store.
|
27
|
+
port (int): The value to store.
|
28
|
+
db (int): The value to store.
|
29
|
+
username (str): The value to store.
|
30
|
+
password (str): The value to store.
|
31
|
+
connection_string (str): The value to store.
|
32
|
+
|
33
|
+
Example:
|
34
|
+
Create a new block from hostname, username and password:
|
35
|
+
```python
|
36
|
+
from prefect.blocks.redis import RedisStorageContainer
|
37
|
+
|
38
|
+
block = RedisStorageContainer.from_host(
|
39
|
+
host="myredishost.com", username="redis", password="SuperSecret")
|
40
|
+
block.save("BLOCK_NAME")
|
41
|
+
```
|
42
|
+
|
43
|
+
Create a new block from a connection string
|
44
|
+
```python
|
45
|
+
from prefect.blocks.redis import RedisStorageContainer
|
46
|
+
block = RedisStorageContainer.from_url(""redis://redis:SuperSecret@myredishost.com:6379")
|
47
|
+
block.save("BLOCK_NAME")
|
48
|
+
```
|
49
|
+
"""
|
50
|
+
|
51
|
+
_logo_url = "https://stprododpcmscdnendpoint.azureedge.net/assets/icons/redis.png"
|
52
|
+
|
53
|
+
host: Optional[str] = Field(default=None, description="Redis hostname")
|
54
|
+
port: int = Field(default=6379, description="Redis port")
|
55
|
+
db: int = Field(default=0, description="Redis DB index")
|
56
|
+
username: Optional[SecretStr] = Field(default=None, description="Redis username")
|
57
|
+
password: Optional[SecretStr] = Field(default=None, description="Redis password")
|
58
|
+
connection_string: Optional[SecretStr] = Field(
|
59
|
+
default=None, description="Redis connection string"
|
60
|
+
)
|
61
|
+
|
62
|
+
def block_initialization(self) -> None:
|
63
|
+
if self.connection_string:
|
64
|
+
return
|
65
|
+
if not self.host:
|
66
|
+
raise ValueError("Initialization error: 'host' is required but missing.")
|
67
|
+
if self.username and not self.password:
|
68
|
+
raise ValueError(
|
69
|
+
"Initialization error: 'username' is provided, but 'password' is missing. Both are required."
|
70
|
+
)
|
71
|
+
|
72
|
+
@sync_compatible
|
73
|
+
async def read_path(self, path: Union[Path, str]):
|
74
|
+
"""Read the redis content at `path`
|
75
|
+
|
76
|
+
Args:
|
77
|
+
path: Redis key to read from
|
78
|
+
|
79
|
+
Returns:
|
80
|
+
Contents at key as bytes
|
81
|
+
"""
|
82
|
+
async with self._client() as client:
|
83
|
+
return await client.get(str(path))
|
84
|
+
|
85
|
+
@sync_compatible
|
86
|
+
async def write_path(self, path: Union[Path, str], content: bytes):
|
87
|
+
"""Write `content` to the redis at `path`
|
88
|
+
|
89
|
+
Args:
|
90
|
+
path: Redis key to write to
|
91
|
+
content: Binary object to write
|
92
|
+
"""
|
93
|
+
|
94
|
+
async with self._client() as client:
|
95
|
+
return await client.set(str(path), content)
|
96
|
+
|
97
|
+
@asynccontextmanager
|
98
|
+
async def _client(self) -> AsyncGenerator[redis.Redis, None]:
|
99
|
+
if self.connection_string:
|
100
|
+
client = redis.Redis.from_url(self.connection_string.get_secret_value())
|
101
|
+
else:
|
102
|
+
assert self.host
|
103
|
+
client = redis.Redis(
|
104
|
+
host=self.host,
|
105
|
+
port=self.port,
|
106
|
+
username=self.username.get_secret_value() if self.username else None,
|
107
|
+
password=self.password.get_secret_value() if self.password else None,
|
108
|
+
db=self.db,
|
109
|
+
)
|
110
|
+
|
111
|
+
try:
|
112
|
+
yield client
|
113
|
+
finally:
|
114
|
+
await client.aclose()
|
115
|
+
|
116
|
+
@classmethod
|
117
|
+
def from_host(
|
118
|
+
cls,
|
119
|
+
host: str,
|
120
|
+
port: int = 6379,
|
121
|
+
db: int = 0,
|
122
|
+
username: Union[None, str, SecretStr] = None,
|
123
|
+
password: Union[None, str, SecretStr] = None,
|
124
|
+
) -> Self:
|
125
|
+
"""Create block from hostname, username and password
|
126
|
+
|
127
|
+
Args:
|
128
|
+
host: Redis hostname
|
129
|
+
username: Redis username
|
130
|
+
password: Redis password
|
131
|
+
port: Redis port
|
132
|
+
|
133
|
+
Returns:
|
134
|
+
`RedisStorageContainer` instance
|
135
|
+
"""
|
136
|
+
|
137
|
+
username = SecretStr(username) if isinstance(username, str) else username
|
138
|
+
password = SecretStr(password) if isinstance(password, str) else password
|
139
|
+
|
140
|
+
return cls(host=host, port=port, db=db, username=username, password=password)
|
141
|
+
|
142
|
+
@classmethod
|
143
|
+
def from_connection_string(cls, connection_string: Union[str, SecretStr]) -> Self:
|
144
|
+
"""Create block from a Redis connection string
|
145
|
+
|
146
|
+
Supports the following URL schemes:
|
147
|
+
- `redis://` creates a TCP socket connection
|
148
|
+
- `rediss://` creates a SSL wrapped TCP socket connection
|
149
|
+
- `unix://` creates a Unix Domain Socket connection
|
150
|
+
|
151
|
+
See [Redis docs](https://redis.readthedocs.io/en/stable/examples
|
152
|
+
/connection_examples.html#Connecting-to-Redis-instances-by-specifying-a-URL
|
153
|
+
-scheme.) for more info.
|
154
|
+
|
155
|
+
Args:
|
156
|
+
connection_string: Redis connection string
|
157
|
+
|
158
|
+
Returns:
|
159
|
+
`RedisStorageContainer` instance
|
160
|
+
"""
|
161
|
+
|
162
|
+
connection_string = (
|
163
|
+
SecretStr(connection_string)
|
164
|
+
if isinstance(connection_string, str)
|
165
|
+
else connection_string
|
166
|
+
)
|
167
|
+
|
168
|
+
return cls(connection_string=connection_string)
|
prefect/blocks/system.py
CHANGED
@@ -1,19 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
import json
|
2
|
+
from typing import Annotated, Any, Generic, TypeVar, Union
|
3
|
+
|
4
|
+
from pydantic import (
|
5
|
+
Field,
|
6
|
+
JsonValue,
|
7
|
+
SecretStr,
|
8
|
+
StrictStr,
|
9
|
+
field_validator,
|
10
|
+
)
|
11
|
+
from pydantic import Secret as PydanticSecret
|
12
|
+
from pydantic_extra_types.pendulum_dt import DateTime as PydanticDateTime
|
13
|
+
|
14
|
+
from prefect._internal.compatibility.deprecated import deprecated_class
|
15
|
+
from prefect.blocks.core import Block
|
4
16
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
17
|
+
_SecretValueType = Union[
|
18
|
+
Annotated[StrictStr, Field(title="string")],
|
19
|
+
Annotated[JsonValue, Field(title="JSON")],
|
20
|
+
]
|
9
21
|
|
10
|
-
|
11
|
-
from prefect.blocks.core import Block
|
22
|
+
T = TypeVar("T", bound=_SecretValueType)
|
12
23
|
|
13
24
|
|
25
|
+
@deprecated_class(
|
26
|
+
start_date="Jun 2024",
|
27
|
+
end_date="Jun 2025",
|
28
|
+
help="Use Variables to store json data instead.",
|
29
|
+
)
|
14
30
|
class JSON(Block):
|
15
31
|
"""
|
16
|
-
A block that represents JSON
|
32
|
+
A block that represents JSON. Deprecated, please use Variables to store JSON data instead.
|
17
33
|
|
18
34
|
Attributes:
|
19
35
|
value: A JSON-compatible value.
|
@@ -33,9 +49,14 @@ class JSON(Block):
|
|
33
49
|
value: Any = Field(default=..., description="A JSON-compatible value.")
|
34
50
|
|
35
51
|
|
52
|
+
@deprecated_class(
|
53
|
+
start_date="Jun 2024",
|
54
|
+
end_date="Jun 2025",
|
55
|
+
help="Use Variables to store string data instead.",
|
56
|
+
)
|
36
57
|
class String(Block):
|
37
58
|
"""
|
38
|
-
A block that represents a string
|
59
|
+
A block that represents a string. Deprecated, please use Variables to store string data instead.
|
39
60
|
|
40
61
|
Attributes:
|
41
62
|
value: A string value.
|
@@ -55,9 +76,14 @@ class String(Block):
|
|
55
76
|
value: str = Field(default=..., description="A string value.")
|
56
77
|
|
57
78
|
|
79
|
+
@deprecated_class(
|
80
|
+
start_date="Jun 2024",
|
81
|
+
end_date="Jun 2025",
|
82
|
+
help="Use Variables to store datetime data instead.",
|
83
|
+
)
|
58
84
|
class DateTime(Block):
|
59
85
|
"""
|
60
|
-
A block that represents a datetime
|
86
|
+
A block that represents a datetime. Deprecated, please use Variables to store datetime data instead.
|
61
87
|
|
62
88
|
Attributes:
|
63
89
|
value: An ISO 8601-compatible datetime value.
|
@@ -75,24 +101,26 @@ class DateTime(Block):
|
|
75
101
|
_logo_url = "https://cdn.sanity.io/images/3ugk85nk/production/8b3da9a6621e92108b8e6a75b82e15374e170ff7-48x48.png"
|
76
102
|
_documentation_url = "https://docs.prefect.io/api-ref/prefect/blocks/system/#prefect.blocks.system.DateTime"
|
77
103
|
|
78
|
-
value:
|
104
|
+
value: PydanticDateTime = Field(
|
79
105
|
default=...,
|
80
106
|
description="An ISO 8601-compatible datetime value.",
|
81
107
|
)
|
82
108
|
|
83
109
|
|
84
|
-
class Secret(Block):
|
110
|
+
class Secret(Block, Generic[T]):
|
85
111
|
"""
|
86
112
|
A block that represents a secret value. The value stored in this block will be obfuscated when
|
87
|
-
this block is
|
113
|
+
this block is viewed or edited in the UI.
|
88
114
|
|
89
115
|
Attributes:
|
90
|
-
value: A
|
116
|
+
value: A value that should be kept secret.
|
91
117
|
|
92
118
|
Example:
|
93
119
|
```python
|
94
120
|
from prefect.blocks.system import Secret
|
95
121
|
|
122
|
+
Secret(value="sk-1234567890").save("BLOCK_NAME", overwrite=True)
|
123
|
+
|
96
124
|
secret_block = Secret.load("BLOCK_NAME")
|
97
125
|
|
98
126
|
# Access the stored secret
|
@@ -103,9 +131,28 @@ class Secret(Block):
|
|
103
131
|
_logo_url = "https://cdn.sanity.io/images/3ugk85nk/production/c6f20e556dd16effda9df16551feecfb5822092b-48x48.png"
|
104
132
|
_documentation_url = "https://docs.prefect.io/api-ref/prefect/blocks/system/#prefect.blocks.system.Secret"
|
105
133
|
|
106
|
-
value: SecretStr = Field(
|
107
|
-
default=...,
|
134
|
+
value: Union[SecretStr, PydanticSecret[T]] = Field(
|
135
|
+
default=...,
|
136
|
+
description="A value that should be kept secret.",
|
137
|
+
examples=["sk-1234567890", {"username": "johndoe", "password": "s3cr3t"}],
|
138
|
+
json_schema_extra={
|
139
|
+
"writeOnly": True,
|
140
|
+
"format": "password",
|
141
|
+
},
|
108
142
|
)
|
109
143
|
|
110
|
-
|
111
|
-
|
144
|
+
@field_validator("value", mode="before")
|
145
|
+
def validate_value(
|
146
|
+
cls, value: Union[T, SecretStr, PydanticSecret[T]]
|
147
|
+
) -> Union[SecretStr, PydanticSecret[T]]:
|
148
|
+
if isinstance(value, (PydanticSecret, SecretStr)):
|
149
|
+
return value
|
150
|
+
else:
|
151
|
+
return PydanticSecret[type(value)](value)
|
152
|
+
|
153
|
+
def get(self) -> T:
|
154
|
+
try:
|
155
|
+
value = self.value.get_secret_value()
|
156
|
+
return json.loads(value)
|
157
|
+
except (TypeError, json.JSONDecodeError):
|
158
|
+
return value
|
prefect/blocks/webhook.py
CHANGED
@@ -1,18 +1,11 @@
|
|
1
1
|
from typing import Optional
|
2
2
|
|
3
3
|
from httpx import AsyncClient, AsyncHTTPTransport, Response
|
4
|
-
|
5
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
6
|
-
|
7
|
-
if HAS_PYDANTIC_V2:
|
8
|
-
from pydantic.v1 import Field, SecretStr
|
9
|
-
else:
|
10
|
-
from pydantic import Field, SecretStr
|
11
|
-
|
4
|
+
from pydantic import Field, SecretStr
|
12
5
|
from typing_extensions import Literal
|
13
6
|
|
14
7
|
from prefect.blocks.core import Block
|
15
|
-
from prefect.
|
8
|
+
from prefect.types import SecretDict
|
16
9
|
|
17
10
|
# Use a global HTTP transport to maintain a process-wide connection pool for
|
18
11
|
# interservice requests
|