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/filesystems.py
CHANGED
@@ -1,33 +1,22 @@
|
|
1
1
|
import abc
|
2
|
-
import io
|
3
|
-
import json
|
4
2
|
import urllib.parse
|
5
3
|
from pathlib import Path
|
6
|
-
from
|
7
|
-
from tempfile import TemporaryDirectory
|
8
|
-
from typing import Any, Dict, Optional, Tuple, Union
|
4
|
+
from typing import Any, Dict, Optional
|
9
5
|
|
10
6
|
import anyio
|
11
7
|
import fsspec
|
12
|
-
|
13
|
-
from prefect._internal.compatibility.deprecated import deprecated_class
|
14
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
15
|
-
|
16
|
-
if HAS_PYDANTIC_V2:
|
17
|
-
from pydantic.v1 import Field, SecretStr, validator
|
18
|
-
else:
|
19
|
-
from pydantic import Field, SecretStr, validator
|
8
|
+
from pydantic import Field, SecretStr, field_validator
|
20
9
|
|
21
10
|
from prefect._internal.schemas.validators import (
|
22
11
|
stringify_path,
|
23
12
|
validate_basepath,
|
24
|
-
validate_github_access_token,
|
25
13
|
)
|
26
14
|
from prefect.blocks.core import Block
|
27
15
|
from prefect.utilities.asyncutils import run_sync_in_worker_thread, sync_compatible
|
28
16
|
from prefect.utilities.compat import copytree
|
29
17
|
from prefect.utilities.filesystem import filter_files
|
30
|
-
|
18
|
+
|
19
|
+
from ._internal.compatibility.migration import getattr_migration
|
31
20
|
|
32
21
|
|
33
22
|
class ReadableFileSystem(Block, abc.ABC):
|
@@ -55,7 +44,7 @@ class ReadableDeploymentStorage(Block, abc.ABC):
|
|
55
44
|
|
56
45
|
@abc.abstractmethod
|
57
46
|
async def get_directory(
|
58
|
-
self, from_path: str = None, local_path: str = None
|
47
|
+
self, from_path: Optional[str] = None, local_path: Optional[str] = None
|
59
48
|
) -> None:
|
60
49
|
pass
|
61
50
|
|
@@ -65,13 +54,16 @@ class WritableDeploymentStorage(Block, abc.ABC):
|
|
65
54
|
|
66
55
|
@abc.abstractmethod
|
67
56
|
async def get_directory(
|
68
|
-
self, from_path: str = None, local_path: str = None
|
57
|
+
self, from_path: Optional[str] = None, local_path: Optional[str] = None
|
69
58
|
) -> None:
|
70
59
|
pass
|
71
60
|
|
72
61
|
@abc.abstractmethod
|
73
62
|
async def put_directory(
|
74
|
-
self,
|
63
|
+
self,
|
64
|
+
local_path: Optional[str] = None,
|
65
|
+
to_path: Optional[str] = None,
|
66
|
+
ignore_file: Optional[str] = None,
|
75
67
|
) -> None:
|
76
68
|
pass
|
77
69
|
|
@@ -99,11 +91,11 @@ class LocalFileSystem(WritableFileSystem, WritableDeploymentStorage):
|
|
99
91
|
default=None, description="Default local path for this block to write to."
|
100
92
|
)
|
101
93
|
|
102
|
-
@
|
94
|
+
@field_validator("basepath", mode="before")
|
103
95
|
def cast_pathlib(cls, value):
|
104
96
|
return stringify_path(value)
|
105
97
|
|
106
|
-
def _resolve_path(self, path: str) -> Path:
|
98
|
+
def _resolve_path(self, path: str, validate: bool = False) -> Path:
|
107
99
|
# Only resolve the base path at runtime, default to the current directory
|
108
100
|
basepath = (
|
109
101
|
Path(self.basepath).expanduser().resolve()
|
@@ -116,22 +108,23 @@ class LocalFileSystem(WritableFileSystem, WritableDeploymentStorage):
|
|
116
108
|
if path is None:
|
117
109
|
return basepath
|
118
110
|
|
119
|
-
|
111
|
+
resolved_path: Path = Path(path).expanduser()
|
120
112
|
|
121
|
-
if not
|
122
|
-
|
113
|
+
if not resolved_path.is_absolute():
|
114
|
+
resolved_path = basepath / resolved_path
|
123
115
|
else:
|
124
|
-
|
125
|
-
|
116
|
+
resolved_path = resolved_path.resolve()
|
117
|
+
|
118
|
+
if validate:
|
119
|
+
if basepath not in resolved_path.parents and (basepath != resolved_path):
|
126
120
|
raise ValueError(
|
127
|
-
f"Provided path {
|
121
|
+
f"Provided path {resolved_path} is outside of the base path {basepath}."
|
128
122
|
)
|
129
|
-
|
130
|
-
return path
|
123
|
+
return resolved_path
|
131
124
|
|
132
125
|
@sync_compatible
|
133
126
|
async def get_directory(
|
134
|
-
self, from_path: str = None, local_path: str = None
|
127
|
+
self, from_path: Optional[str] = None, local_path: Optional[str] = None
|
135
128
|
) -> None:
|
136
129
|
"""
|
137
130
|
Copies a directory from one place to another on the local filesystem.
|
@@ -181,7 +174,10 @@ class LocalFileSystem(WritableFileSystem, WritableDeploymentStorage):
|
|
181
174
|
|
182
175
|
@sync_compatible
|
183
176
|
async def put_directory(
|
184
|
-
self,
|
177
|
+
self,
|
178
|
+
local_path: Optional[str] = None,
|
179
|
+
to_path: Optional[str] = None,
|
180
|
+
ignore_file: Optional[str] = None,
|
185
181
|
) -> None:
|
186
182
|
"""
|
187
183
|
Copies a directory from one place to another on the local filesystem.
|
@@ -189,7 +185,7 @@ class LocalFileSystem(WritableFileSystem, WritableDeploymentStorage):
|
|
189
185
|
Defaults to copying the entire contents of the current working directory to the block's basepath.
|
190
186
|
An `ignore_file` path may be provided that can include gitignore style expressions for filepaths to ignore.
|
191
187
|
"""
|
192
|
-
destination_path = self._resolve_path(to_path)
|
188
|
+
destination_path = self._resolve_path(to_path, validate=True)
|
193
189
|
|
194
190
|
if not local_path:
|
195
191
|
local_path = Path(".").absolute()
|
@@ -280,7 +276,7 @@ class RemoteFileSystem(WritableFileSystem, WritableDeploymentStorage):
|
|
280
276
|
# Cache for the configured fsspec file system used for access
|
281
277
|
_filesystem: fsspec.AbstractFileSystem = None
|
282
278
|
|
283
|
-
@
|
279
|
+
@field_validator("basepath")
|
284
280
|
def check_basepath(cls, value):
|
285
281
|
return validate_basepath(value)
|
286
282
|
|
@@ -422,368 +418,6 @@ class RemoteFileSystem(WritableFileSystem, WritableDeploymentStorage):
|
|
422
418
|
return self._filesystem
|
423
419
|
|
424
420
|
|
425
|
-
@deprecated_class(
|
426
|
-
start_date="Mar 2024", help="Use the `S3Bucket` block from prefect-aws instead."
|
427
|
-
)
|
428
|
-
class S3(WritableFileSystem, WritableDeploymentStorage):
|
429
|
-
"""
|
430
|
-
DEPRECATION WARNING:
|
431
|
-
|
432
|
-
This class is deprecated as of March 2024 and will not be available after September 2024.
|
433
|
-
It has been replaced by `S3Bucket` from the `prefect-aws` package, which offers enhanced functionality
|
434
|
-
and better a better user experience.
|
435
|
-
|
436
|
-
Store data as a file on AWS S3.
|
437
|
-
|
438
|
-
Example:
|
439
|
-
Load stored S3 config:
|
440
|
-
```python
|
441
|
-
from prefect.filesystems import S3
|
442
|
-
|
443
|
-
s3_block = S3.load("BLOCK_NAME")
|
444
|
-
```
|
445
|
-
"""
|
446
|
-
|
447
|
-
_block_type_name = "S3"
|
448
|
-
_logo_url = "https://cdn.sanity.io/images/3ugk85nk/production/d74b16fe84ce626345adf235a47008fea2869a60-225x225.png"
|
449
|
-
_documentation_url = "https://docs.prefect.io/concepts/filesystems/#s3"
|
450
|
-
|
451
|
-
bucket_path: str = Field(
|
452
|
-
default=...,
|
453
|
-
description="An S3 bucket path.",
|
454
|
-
examples=["my-bucket/a-directory-within"],
|
455
|
-
)
|
456
|
-
aws_access_key_id: Optional[SecretStr] = Field(
|
457
|
-
default=None,
|
458
|
-
title="AWS Access Key ID",
|
459
|
-
description="Equivalent to the AWS_ACCESS_KEY_ID environment variable.",
|
460
|
-
examples=["AKIAIOSFODNN7EXAMPLE"],
|
461
|
-
)
|
462
|
-
aws_secret_access_key: Optional[SecretStr] = Field(
|
463
|
-
default=None,
|
464
|
-
title="AWS Secret Access Key",
|
465
|
-
description="Equivalent to the AWS_SECRET_ACCESS_KEY environment variable.",
|
466
|
-
examples=["wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"],
|
467
|
-
)
|
468
|
-
|
469
|
-
_remote_file_system: RemoteFileSystem = None
|
470
|
-
|
471
|
-
@property
|
472
|
-
def basepath(self) -> str:
|
473
|
-
return f"s3://{self.bucket_path}"
|
474
|
-
|
475
|
-
@property
|
476
|
-
def filesystem(self) -> RemoteFileSystem:
|
477
|
-
settings = {}
|
478
|
-
if self.aws_access_key_id:
|
479
|
-
settings["key"] = self.aws_access_key_id.get_secret_value()
|
480
|
-
if self.aws_secret_access_key:
|
481
|
-
settings["secret"] = self.aws_secret_access_key.get_secret_value()
|
482
|
-
self._remote_file_system = RemoteFileSystem(
|
483
|
-
basepath=f"s3://{self.bucket_path}", settings=settings
|
484
|
-
)
|
485
|
-
return self._remote_file_system
|
486
|
-
|
487
|
-
@sync_compatible
|
488
|
-
async def get_directory(
|
489
|
-
self, from_path: Optional[str] = None, local_path: Optional[str] = None
|
490
|
-
) -> bytes:
|
491
|
-
"""
|
492
|
-
Downloads a directory from a given remote path to a local directory.
|
493
|
-
|
494
|
-
Defaults to downloading the entire contents of the block's basepath to the current working directory.
|
495
|
-
"""
|
496
|
-
return await self.filesystem.get_directory(
|
497
|
-
from_path=from_path, local_path=local_path
|
498
|
-
)
|
499
|
-
|
500
|
-
@sync_compatible
|
501
|
-
async def put_directory(
|
502
|
-
self,
|
503
|
-
local_path: Optional[str] = None,
|
504
|
-
to_path: Optional[str] = None,
|
505
|
-
ignore_file: Optional[str] = None,
|
506
|
-
) -> int:
|
507
|
-
"""
|
508
|
-
Uploads a directory from a given local path to a remote directory.
|
509
|
-
|
510
|
-
Defaults to uploading the entire contents of the current working directory to the block's basepath.
|
511
|
-
"""
|
512
|
-
return await self.filesystem.put_directory(
|
513
|
-
local_path=local_path, to_path=to_path, ignore_file=ignore_file
|
514
|
-
)
|
515
|
-
|
516
|
-
@sync_compatible
|
517
|
-
async def read_path(self, path: str) -> bytes:
|
518
|
-
return await self.filesystem.read_path(path)
|
519
|
-
|
520
|
-
@sync_compatible
|
521
|
-
async def write_path(self, path: str, content: bytes) -> str:
|
522
|
-
return await self.filesystem.write_path(path=path, content=content)
|
523
|
-
|
524
|
-
|
525
|
-
@deprecated_class(
|
526
|
-
start_date="Mar 2024", help="Use the `GcsBucket` block from prefect-gcp instead."
|
527
|
-
)
|
528
|
-
class GCS(WritableFileSystem, WritableDeploymentStorage):
|
529
|
-
"""
|
530
|
-
DEPRECATION WARNING:
|
531
|
-
|
532
|
-
This class is deprecated as of March 2024 and will not be available after September 2024.
|
533
|
-
It has been replaced by `GcsBucket` from the `prefect-gcp` package, which offers enhanced functionality
|
534
|
-
and better a better user experience.
|
535
|
-
Store data as a file on Google Cloud Storage.
|
536
|
-
|
537
|
-
Example:
|
538
|
-
Load stored GCS config:
|
539
|
-
```python
|
540
|
-
from prefect.filesystems import GCS
|
541
|
-
|
542
|
-
gcs_block = GCS.load("BLOCK_NAME")
|
543
|
-
```
|
544
|
-
"""
|
545
|
-
|
546
|
-
_logo_url = "https://cdn.sanity.io/images/3ugk85nk/production/422d13bb838cf247eb2b2cf229ce6a2e717d601b-256x256.png"
|
547
|
-
_documentation_url = "https://docs.prefect.io/concepts/filesystems/#gcs"
|
548
|
-
|
549
|
-
bucket_path: str = Field(
|
550
|
-
default=...,
|
551
|
-
description="A GCS bucket path.",
|
552
|
-
examples=["my-bucket/a-directory-within"],
|
553
|
-
)
|
554
|
-
service_account_info: Optional[SecretStr] = Field(
|
555
|
-
default=None,
|
556
|
-
description="The contents of a service account keyfile as a JSON string.",
|
557
|
-
)
|
558
|
-
project: Optional[str] = Field(
|
559
|
-
default=None,
|
560
|
-
description=(
|
561
|
-
"The project the GCS bucket resides in. If not provided, the project will"
|
562
|
-
" be inferred from the credentials or environment."
|
563
|
-
),
|
564
|
-
)
|
565
|
-
|
566
|
-
@property
|
567
|
-
def basepath(self) -> str:
|
568
|
-
return f"gcs://{self.bucket_path}"
|
569
|
-
|
570
|
-
@property
|
571
|
-
def filesystem(self) -> RemoteFileSystem:
|
572
|
-
settings = {}
|
573
|
-
if self.service_account_info:
|
574
|
-
try:
|
575
|
-
settings["token"] = json.loads(
|
576
|
-
self.service_account_info.get_secret_value()
|
577
|
-
)
|
578
|
-
except json.JSONDecodeError:
|
579
|
-
raise ValueError(
|
580
|
-
"Unable to load provided service_account_info. Please make sure"
|
581
|
-
" that the provided value is a valid JSON string."
|
582
|
-
)
|
583
|
-
remote_file_system = RemoteFileSystem(
|
584
|
-
basepath=f"gcs://{self.bucket_path}", settings=settings
|
585
|
-
)
|
586
|
-
return remote_file_system
|
587
|
-
|
588
|
-
@sync_compatible
|
589
|
-
async def get_directory(
|
590
|
-
self, from_path: Optional[str] = None, local_path: Optional[str] = None
|
591
|
-
) -> bytes:
|
592
|
-
"""
|
593
|
-
Downloads a directory from a given remote path to a local directory.
|
594
|
-
|
595
|
-
Defaults to downloading the entire contents of the block's basepath to the current working directory.
|
596
|
-
"""
|
597
|
-
return await self.filesystem.get_directory(
|
598
|
-
from_path=from_path, local_path=local_path
|
599
|
-
)
|
600
|
-
|
601
|
-
@sync_compatible
|
602
|
-
async def put_directory(
|
603
|
-
self,
|
604
|
-
local_path: Optional[str] = None,
|
605
|
-
to_path: Optional[str] = None,
|
606
|
-
ignore_file: Optional[str] = None,
|
607
|
-
) -> int:
|
608
|
-
"""
|
609
|
-
Uploads a directory from a given local path to a remote directory.
|
610
|
-
|
611
|
-
Defaults to uploading the entire contents of the current working directory to the block's basepath.
|
612
|
-
"""
|
613
|
-
return await self.filesystem.put_directory(
|
614
|
-
local_path=local_path, to_path=to_path, ignore_file=ignore_file
|
615
|
-
)
|
616
|
-
|
617
|
-
@sync_compatible
|
618
|
-
async def read_path(self, path: str) -> bytes:
|
619
|
-
return await self.filesystem.read_path(path)
|
620
|
-
|
621
|
-
@sync_compatible
|
622
|
-
async def write_path(self, path: str, content: bytes) -> str:
|
623
|
-
return await self.filesystem.write_path(path=path, content=content)
|
624
|
-
|
625
|
-
|
626
|
-
@deprecated_class(
|
627
|
-
start_date="Mar 2024",
|
628
|
-
help="Use the `AzureBlobStorageContainer` block from prefect-azure instead.",
|
629
|
-
)
|
630
|
-
class Azure(WritableFileSystem, WritableDeploymentStorage):
|
631
|
-
"""
|
632
|
-
DEPRECATION WARNING:
|
633
|
-
|
634
|
-
This class is deprecated as of March 2024 and will not be available after September 2024.
|
635
|
-
It has been replaced by `AzureBlobStorageContainer` from the `prefect-azure` package, which
|
636
|
-
offers enhanced functionality and better a better user experience.
|
637
|
-
|
638
|
-
Store data as a file on Azure Datalake and Azure Blob Storage.
|
639
|
-
|
640
|
-
Example:
|
641
|
-
Load stored Azure config:
|
642
|
-
```python
|
643
|
-
from prefect.filesystems import Azure
|
644
|
-
|
645
|
-
az_block = Azure.load("BLOCK_NAME")
|
646
|
-
```
|
647
|
-
"""
|
648
|
-
|
649
|
-
_block_type_name = "Azure"
|
650
|
-
_logo_url = "https://cdn.sanity.io/images/3ugk85nk/production/54e3fa7e00197a4fbd1d82ed62494cb58d08c96a-250x250.png"
|
651
|
-
_documentation_url = "https://docs.prefect.io/concepts/filesystems/#azure"
|
652
|
-
|
653
|
-
bucket_path: str = Field(
|
654
|
-
default=...,
|
655
|
-
description="An Azure storage bucket path.",
|
656
|
-
examples=["my-bucket/a-directory-within"],
|
657
|
-
)
|
658
|
-
azure_storage_connection_string: Optional[SecretStr] = Field(
|
659
|
-
default=None,
|
660
|
-
title="Azure storage connection string",
|
661
|
-
description=(
|
662
|
-
"Equivalent to the AZURE_STORAGE_CONNECTION_STRING environment variable."
|
663
|
-
),
|
664
|
-
)
|
665
|
-
azure_storage_account_name: Optional[SecretStr] = Field(
|
666
|
-
default=None,
|
667
|
-
title="Azure storage account name",
|
668
|
-
description=(
|
669
|
-
"Equivalent to the AZURE_STORAGE_ACCOUNT_NAME environment variable."
|
670
|
-
),
|
671
|
-
)
|
672
|
-
azure_storage_account_key: Optional[SecretStr] = Field(
|
673
|
-
default=None,
|
674
|
-
title="Azure storage account key",
|
675
|
-
description="Equivalent to the AZURE_STORAGE_ACCOUNT_KEY environment variable.",
|
676
|
-
)
|
677
|
-
azure_storage_tenant_id: Optional[SecretStr] = Field(
|
678
|
-
None,
|
679
|
-
title="Azure storage tenant ID",
|
680
|
-
description="Equivalent to the AZURE_TENANT_ID environment variable.",
|
681
|
-
)
|
682
|
-
azure_storage_client_id: Optional[SecretStr] = Field(
|
683
|
-
None,
|
684
|
-
title="Azure storage client ID",
|
685
|
-
description="Equivalent to the AZURE_CLIENT_ID environment variable.",
|
686
|
-
)
|
687
|
-
azure_storage_client_secret: Optional[SecretStr] = Field(
|
688
|
-
None,
|
689
|
-
title="Azure storage client secret",
|
690
|
-
description="Equivalent to the AZURE_CLIENT_SECRET environment variable.",
|
691
|
-
)
|
692
|
-
azure_storage_anon: bool = Field(
|
693
|
-
default=True,
|
694
|
-
title="Azure storage anonymous connection",
|
695
|
-
description=(
|
696
|
-
"Set the 'anon' flag for ADLFS. This should be False for systems that"
|
697
|
-
" require ADLFS to use DefaultAzureCredentials."
|
698
|
-
),
|
699
|
-
)
|
700
|
-
azure_storage_container: Optional[SecretStr] = Field(
|
701
|
-
default=None,
|
702
|
-
title="Azure storage container",
|
703
|
-
description=(
|
704
|
-
"Blob Container in Azure Storage Account. If set the 'bucket_path' will"
|
705
|
-
" be interpreted using the following URL format:"
|
706
|
-
"'az://<container>@<storage_account>.dfs.core.windows.net/<bucket_path>'."
|
707
|
-
),
|
708
|
-
)
|
709
|
-
_remote_file_system: RemoteFileSystem = None
|
710
|
-
|
711
|
-
@property
|
712
|
-
def basepath(self) -> str:
|
713
|
-
if self.azure_storage_container:
|
714
|
-
return (
|
715
|
-
f"az://{self.azure_storage_container.get_secret_value()}"
|
716
|
-
f"@{self.azure_storage_account_name.get_secret_value()}"
|
717
|
-
f".dfs.core.windows.net/{self.bucket_path}"
|
718
|
-
)
|
719
|
-
else:
|
720
|
-
return f"az://{self.bucket_path}"
|
721
|
-
|
722
|
-
@property
|
723
|
-
def filesystem(self) -> RemoteFileSystem:
|
724
|
-
settings = {}
|
725
|
-
if self.azure_storage_connection_string:
|
726
|
-
settings[
|
727
|
-
"connection_string"
|
728
|
-
] = self.azure_storage_connection_string.get_secret_value()
|
729
|
-
if self.azure_storage_account_name:
|
730
|
-
settings[
|
731
|
-
"account_name"
|
732
|
-
] = self.azure_storage_account_name.get_secret_value()
|
733
|
-
if self.azure_storage_account_key:
|
734
|
-
settings["account_key"] = self.azure_storage_account_key.get_secret_value()
|
735
|
-
if self.azure_storage_tenant_id:
|
736
|
-
settings["tenant_id"] = self.azure_storage_tenant_id.get_secret_value()
|
737
|
-
if self.azure_storage_client_id:
|
738
|
-
settings["client_id"] = self.azure_storage_client_id.get_secret_value()
|
739
|
-
if self.azure_storage_client_secret:
|
740
|
-
settings[
|
741
|
-
"client_secret"
|
742
|
-
] = self.azure_storage_client_secret.get_secret_value()
|
743
|
-
settings["anon"] = self.azure_storage_anon
|
744
|
-
self._remote_file_system = RemoteFileSystem(
|
745
|
-
basepath=self.basepath, settings=settings
|
746
|
-
)
|
747
|
-
return self._remote_file_system
|
748
|
-
|
749
|
-
@sync_compatible
|
750
|
-
async def get_directory(
|
751
|
-
self, from_path: Optional[str] = None, local_path: Optional[str] = None
|
752
|
-
) -> bytes:
|
753
|
-
"""
|
754
|
-
Downloads a directory from a given remote path to a local directory.
|
755
|
-
|
756
|
-
Defaults to downloading the entire contents of the block's basepath to the current working directory.
|
757
|
-
"""
|
758
|
-
return await self.filesystem.get_directory(
|
759
|
-
from_path=from_path, local_path=local_path
|
760
|
-
)
|
761
|
-
|
762
|
-
@sync_compatible
|
763
|
-
async def put_directory(
|
764
|
-
self,
|
765
|
-
local_path: Optional[str] = None,
|
766
|
-
to_path: Optional[str] = None,
|
767
|
-
ignore_file: Optional[str] = None,
|
768
|
-
) -> int:
|
769
|
-
"""
|
770
|
-
Uploads a directory from a given local path to a remote directory.
|
771
|
-
|
772
|
-
Defaults to uploading the entire contents of the current working directory to the block's basepath.
|
773
|
-
"""
|
774
|
-
return await self.filesystem.put_directory(
|
775
|
-
local_path=local_path, to_path=to_path, ignore_file=ignore_file
|
776
|
-
)
|
777
|
-
|
778
|
-
@sync_compatible
|
779
|
-
async def read_path(self, path: str) -> bytes:
|
780
|
-
return await self.filesystem.read_path(path)
|
781
|
-
|
782
|
-
@sync_compatible
|
783
|
-
async def write_path(self, path: str, content: bytes) -> str:
|
784
|
-
return await self.filesystem.write_path(path=path, content=content)
|
785
|
-
|
786
|
-
|
787
421
|
class SMB(WritableFileSystem, WritableDeploymentStorage):
|
788
422
|
"""
|
789
423
|
Store data as a file on a SMB share.
|
@@ -815,7 +449,7 @@ class SMB(WritableFileSystem, WritableDeploymentStorage):
|
|
815
449
|
default=None, title="SMB Password", description="Password for SMB access."
|
816
450
|
)
|
817
451
|
smb_host: str = Field(
|
818
|
-
default=...,
|
452
|
+
default=..., title="SMB server/hostname", description="SMB server/hostname."
|
819
453
|
)
|
820
454
|
smb_port: Optional[int] = Field(
|
821
455
|
default=None, title="SMB port", description="SMB port (default: 445)."
|
@@ -883,137 +517,4 @@ class SMB(WritableFileSystem, WritableDeploymentStorage):
|
|
883
517
|
return await self.filesystem.write_path(path=path, content=content)
|
884
518
|
|
885
519
|
|
886
|
-
|
887
|
-
start_date="Mar 2024",
|
888
|
-
help="Use the `GitHubRepository` block from prefect-github instead.",
|
889
|
-
)
|
890
|
-
class GitHub(ReadableDeploymentStorage):
|
891
|
-
"""
|
892
|
-
DEPRECATION WARNING:
|
893
|
-
|
894
|
-
This class is deprecated as of March 2024 and will not be available after September 2024.
|
895
|
-
It has been replaced by `GitHubRepository` from the `prefect-github` package, which offers
|
896
|
-
enhanced functionality and better a better user experience.
|
897
|
-
q
|
898
|
-
Interact with files stored on GitHub repositories.
|
899
|
-
"""
|
900
|
-
|
901
|
-
_block_type_name = "GitHub"
|
902
|
-
_logo_url = "https://cdn.sanity.io/images/3ugk85nk/production/41971cfecfea5f79ff334164f06ecb34d1038dd4-250x250.png"
|
903
|
-
_documentation_url = "https://docs.prefect.io/concepts/filesystems/#github"
|
904
|
-
|
905
|
-
repository: str = Field(
|
906
|
-
default=...,
|
907
|
-
description=(
|
908
|
-
"The URL of a GitHub repository to read from, in either HTTPS or SSH"
|
909
|
-
" format."
|
910
|
-
),
|
911
|
-
)
|
912
|
-
reference: Optional[str] = Field(
|
913
|
-
default=None,
|
914
|
-
description="An optional reference to pin to; can be a branch name or tag.",
|
915
|
-
)
|
916
|
-
access_token: Optional[SecretStr] = Field(
|
917
|
-
name="Personal Access Token",
|
918
|
-
default=None,
|
919
|
-
description=(
|
920
|
-
"A GitHub Personal Access Token (PAT) with repo scope."
|
921
|
-
" To use a fine-grained PAT, provide '{username}:{PAT}' as the value."
|
922
|
-
),
|
923
|
-
)
|
924
|
-
include_git_objects: bool = Field(
|
925
|
-
default=True,
|
926
|
-
description=(
|
927
|
-
"Whether to include git objects when copying the repo contents to a"
|
928
|
-
" directory."
|
929
|
-
),
|
930
|
-
)
|
931
|
-
|
932
|
-
@validator("access_token")
|
933
|
-
def _ensure_credentials_go_with_https(cls, v: str, values: dict) -> str:
|
934
|
-
return validate_github_access_token(v, values)
|
935
|
-
|
936
|
-
def _create_repo_url(self) -> str:
|
937
|
-
"""Format the URL provided to the `git clone` command.
|
938
|
-
|
939
|
-
For private repos: https://<oauth-key>@github.com/<username>/<repo>.git
|
940
|
-
All other repos should be the same as `self.repository`.
|
941
|
-
"""
|
942
|
-
url_components = urllib.parse.urlparse(self.repository)
|
943
|
-
if url_components.scheme == "https" and self.access_token is not None:
|
944
|
-
updated_components = url_components._replace(
|
945
|
-
netloc=f"{self.access_token.get_secret_value()}@{url_components.netloc}"
|
946
|
-
)
|
947
|
-
full_url = urllib.parse.urlunparse(updated_components)
|
948
|
-
else:
|
949
|
-
full_url = self.repository
|
950
|
-
|
951
|
-
return full_url
|
952
|
-
|
953
|
-
@staticmethod
|
954
|
-
def _get_paths(
|
955
|
-
dst_dir: Union[str, None], src_dir: str, sub_directory: str
|
956
|
-
) -> Tuple[str, str]:
|
957
|
-
"""Returns the fully formed paths for GitHubRepository contents in the form
|
958
|
-
(content_source, content_destination).
|
959
|
-
"""
|
960
|
-
if dst_dir is None:
|
961
|
-
content_destination = Path(".").absolute()
|
962
|
-
else:
|
963
|
-
content_destination = Path(dst_dir)
|
964
|
-
|
965
|
-
content_source = Path(src_dir)
|
966
|
-
|
967
|
-
if sub_directory:
|
968
|
-
content_destination = content_destination.joinpath(sub_directory)
|
969
|
-
content_source = content_source.joinpath(sub_directory)
|
970
|
-
|
971
|
-
return str(content_source), str(content_destination)
|
972
|
-
|
973
|
-
@sync_compatible
|
974
|
-
async def get_directory(
|
975
|
-
self, from_path: Optional[str] = None, local_path: Optional[str] = None
|
976
|
-
) -> None:
|
977
|
-
"""
|
978
|
-
Clones a GitHub project specified in `from_path` to the provided `local_path`;
|
979
|
-
defaults to cloning the repository reference configured on the Block to the
|
980
|
-
present working directory.
|
981
|
-
|
982
|
-
Args:
|
983
|
-
from_path: If provided, interpreted as a subdirectory of the underlying
|
984
|
-
repository that will be copied to the provided local path.
|
985
|
-
local_path: A local path to clone to; defaults to present working directory.
|
986
|
-
"""
|
987
|
-
# CONSTRUCT COMMAND
|
988
|
-
cmd = ["git", "clone", self._create_repo_url()]
|
989
|
-
if self.reference:
|
990
|
-
cmd += ["-b", self.reference]
|
991
|
-
|
992
|
-
# Limit git history
|
993
|
-
cmd += ["--depth", "1"]
|
994
|
-
|
995
|
-
# Clone to a temporary directory and move the subdirectory over
|
996
|
-
with TemporaryDirectory(suffix="prefect") as tmp_dir:
|
997
|
-
cmd.append(tmp_dir)
|
998
|
-
|
999
|
-
err_stream = io.StringIO()
|
1000
|
-
out_stream = io.StringIO()
|
1001
|
-
process = await run_process(cmd, stream_output=(out_stream, err_stream))
|
1002
|
-
if process.returncode != 0:
|
1003
|
-
err_stream.seek(0)
|
1004
|
-
raise OSError(f"Failed to pull from remote:\n {err_stream.read()}")
|
1005
|
-
|
1006
|
-
content_source, content_destination = self._get_paths(
|
1007
|
-
dst_dir=local_path, src_dir=tmp_dir, sub_directory=from_path
|
1008
|
-
)
|
1009
|
-
|
1010
|
-
ignore_func = None
|
1011
|
-
if not self.include_git_objects:
|
1012
|
-
ignore_func = ignore_patterns(".git")
|
1013
|
-
|
1014
|
-
copytree(
|
1015
|
-
src=content_source,
|
1016
|
-
dst=content_destination,
|
1017
|
-
dirs_exist_ok=True,
|
1018
|
-
ignore=ignore_func,
|
1019
|
-
)
|
520
|
+
__getattr__ = getattr_migration(__name__)
|