prefect-client 2.20.2__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.
Files changed (288) hide show
  1. prefect/__init__.py +74 -110
  2. prefect/_internal/compatibility/deprecated.py +6 -115
  3. prefect/_internal/compatibility/experimental.py +4 -79
  4. prefect/_internal/compatibility/migration.py +166 -0
  5. prefect/_internal/concurrency/__init__.py +2 -2
  6. prefect/_internal/concurrency/api.py +1 -35
  7. prefect/_internal/concurrency/calls.py +0 -6
  8. prefect/_internal/concurrency/cancellation.py +0 -3
  9. prefect/_internal/concurrency/event_loop.py +0 -20
  10. prefect/_internal/concurrency/inspection.py +3 -3
  11. prefect/_internal/concurrency/primitives.py +1 -0
  12. prefect/_internal/concurrency/services.py +23 -0
  13. prefect/_internal/concurrency/threads.py +35 -0
  14. prefect/_internal/concurrency/waiters.py +0 -28
  15. prefect/_internal/integrations.py +7 -0
  16. prefect/_internal/pydantic/__init__.py +0 -45
  17. prefect/_internal/pydantic/annotations/pendulum.py +2 -2
  18. prefect/_internal/pydantic/v1_schema.py +21 -22
  19. prefect/_internal/pydantic/v2_schema.py +0 -2
  20. prefect/_internal/pydantic/v2_validated_func.py +18 -23
  21. prefect/_internal/pytz.py +1 -1
  22. prefect/_internal/retries.py +61 -0
  23. prefect/_internal/schemas/bases.py +45 -177
  24. prefect/_internal/schemas/fields.py +1 -43
  25. prefect/_internal/schemas/validators.py +47 -233
  26. prefect/agent.py +3 -695
  27. prefect/artifacts.py +173 -14
  28. prefect/automations.py +39 -4
  29. prefect/blocks/abstract.py +1 -1
  30. prefect/blocks/core.py +423 -164
  31. prefect/blocks/fields.py +2 -57
  32. prefect/blocks/notifications.py +43 -28
  33. prefect/blocks/redis.py +168 -0
  34. prefect/blocks/system.py +67 -20
  35. prefect/blocks/webhook.py +2 -9
  36. prefect/cache_policies.py +239 -0
  37. prefect/client/__init__.py +4 -0
  38. prefect/client/base.py +33 -27
  39. prefect/client/cloud.py +65 -20
  40. prefect/client/collections.py +1 -1
  41. prefect/client/orchestration.py +667 -440
  42. prefect/client/schemas/actions.py +115 -100
  43. prefect/client/schemas/filters.py +46 -52
  44. prefect/client/schemas/objects.py +228 -178
  45. prefect/client/schemas/responses.py +18 -36
  46. prefect/client/schemas/schedules.py +55 -36
  47. prefect/client/schemas/sorting.py +2 -0
  48. prefect/client/subscriptions.py +8 -7
  49. prefect/client/types/flexible_schedule_list.py +11 -0
  50. prefect/client/utilities.py +9 -6
  51. prefect/concurrency/asyncio.py +60 -11
  52. prefect/concurrency/context.py +24 -0
  53. prefect/concurrency/events.py +2 -2
  54. prefect/concurrency/services.py +46 -16
  55. prefect/concurrency/sync.py +51 -7
  56. prefect/concurrency/v1/asyncio.py +143 -0
  57. prefect/concurrency/v1/context.py +27 -0
  58. prefect/concurrency/v1/events.py +61 -0
  59. prefect/concurrency/v1/services.py +116 -0
  60. prefect/concurrency/v1/sync.py +92 -0
  61. prefect/context.py +246 -149
  62. prefect/deployments/__init__.py +33 -18
  63. prefect/deployments/base.py +10 -15
  64. prefect/deployments/deployments.py +2 -1048
  65. prefect/deployments/flow_runs.py +178 -0
  66. prefect/deployments/runner.py +72 -173
  67. prefect/deployments/schedules.py +31 -25
  68. prefect/deployments/steps/__init__.py +0 -1
  69. prefect/deployments/steps/core.py +7 -0
  70. prefect/deployments/steps/pull.py +15 -21
  71. prefect/deployments/steps/utility.py +2 -1
  72. prefect/docker/__init__.py +20 -0
  73. prefect/docker/docker_image.py +82 -0
  74. prefect/engine.py +15 -2466
  75. prefect/events/actions.py +17 -23
  76. prefect/events/cli/automations.py +20 -7
  77. prefect/events/clients.py +142 -80
  78. prefect/events/filters.py +14 -18
  79. prefect/events/related.py +74 -75
  80. prefect/events/schemas/__init__.py +0 -5
  81. prefect/events/schemas/automations.py +55 -46
  82. prefect/events/schemas/deployment_triggers.py +7 -197
  83. prefect/events/schemas/events.py +46 -65
  84. prefect/events/schemas/labelling.py +10 -14
  85. prefect/events/utilities.py +4 -5
  86. prefect/events/worker.py +23 -8
  87. prefect/exceptions.py +15 -0
  88. prefect/filesystems.py +30 -529
  89. prefect/flow_engine.py +827 -0
  90. prefect/flow_runs.py +379 -7
  91. prefect/flows.py +470 -360
  92. prefect/futures.py +382 -331
  93. prefect/infrastructure/__init__.py +5 -26
  94. prefect/infrastructure/base.py +3 -320
  95. prefect/infrastructure/provisioners/__init__.py +5 -3
  96. prefect/infrastructure/provisioners/cloud_run.py +13 -8
  97. prefect/infrastructure/provisioners/container_instance.py +14 -9
  98. prefect/infrastructure/provisioners/ecs.py +10 -8
  99. prefect/infrastructure/provisioners/modal.py +8 -5
  100. prefect/input/__init__.py +4 -0
  101. prefect/input/actions.py +2 -4
  102. prefect/input/run_input.py +9 -9
  103. prefect/logging/formatters.py +2 -4
  104. prefect/logging/handlers.py +9 -14
  105. prefect/logging/loggers.py +5 -5
  106. prefect/main.py +72 -0
  107. prefect/plugins.py +2 -64
  108. prefect/profiles.toml +16 -2
  109. prefect/records/__init__.py +1 -0
  110. prefect/records/base.py +223 -0
  111. prefect/records/filesystem.py +207 -0
  112. prefect/records/memory.py +178 -0
  113. prefect/records/result_store.py +64 -0
  114. prefect/results.py +577 -504
  115. prefect/runner/runner.py +124 -51
  116. prefect/runner/server.py +32 -34
  117. prefect/runner/storage.py +3 -12
  118. prefect/runner/submit.py +2 -10
  119. prefect/runner/utils.py +2 -2
  120. prefect/runtime/__init__.py +1 -0
  121. prefect/runtime/deployment.py +1 -0
  122. prefect/runtime/flow_run.py +40 -5
  123. prefect/runtime/task_run.py +1 -0
  124. prefect/serializers.py +28 -39
  125. prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
  126. prefect/settings.py +209 -332
  127. prefect/states.py +160 -63
  128. prefect/task_engine.py +1478 -57
  129. prefect/task_runners.py +383 -287
  130. prefect/task_runs.py +240 -0
  131. prefect/task_worker.py +463 -0
  132. prefect/tasks.py +684 -374
  133. prefect/transactions.py +410 -0
  134. prefect/types/__init__.py +72 -86
  135. prefect/types/entrypoint.py +13 -0
  136. prefect/utilities/annotations.py +4 -3
  137. prefect/utilities/asyncutils.py +227 -148
  138. prefect/utilities/callables.py +138 -48
  139. prefect/utilities/collections.py +134 -86
  140. prefect/utilities/dispatch.py +27 -14
  141. prefect/utilities/dockerutils.py +11 -4
  142. prefect/utilities/engine.py +186 -32
  143. prefect/utilities/filesystem.py +4 -5
  144. prefect/utilities/importtools.py +26 -27
  145. prefect/utilities/pydantic.py +128 -38
  146. prefect/utilities/schema_tools/hydration.py +18 -1
  147. prefect/utilities/schema_tools/validation.py +30 -0
  148. prefect/utilities/services.py +35 -9
  149. prefect/utilities/templating.py +12 -2
  150. prefect/utilities/timeout.py +20 -5
  151. prefect/utilities/urls.py +195 -0
  152. prefect/utilities/visualization.py +1 -0
  153. prefect/variables.py +78 -59
  154. prefect/workers/__init__.py +0 -1
  155. prefect/workers/base.py +237 -244
  156. prefect/workers/block.py +5 -226
  157. prefect/workers/cloud.py +6 -0
  158. prefect/workers/process.py +265 -12
  159. prefect/workers/server.py +29 -11
  160. {prefect_client-2.20.2.dist-info → prefect_client-3.0.0.dist-info}/METADATA +30 -26
  161. prefect_client-3.0.0.dist-info/RECORD +201 -0
  162. {prefect_client-2.20.2.dist-info → prefect_client-3.0.0.dist-info}/WHEEL +1 -1
  163. prefect/_internal/pydantic/_base_model.py +0 -51
  164. prefect/_internal/pydantic/_compat.py +0 -82
  165. prefect/_internal/pydantic/_flags.py +0 -20
  166. prefect/_internal/pydantic/_types.py +0 -8
  167. prefect/_internal/pydantic/utilities/config_dict.py +0 -72
  168. prefect/_internal/pydantic/utilities/field_validator.py +0 -150
  169. prefect/_internal/pydantic/utilities/model_construct.py +0 -56
  170. prefect/_internal/pydantic/utilities/model_copy.py +0 -55
  171. prefect/_internal/pydantic/utilities/model_dump.py +0 -136
  172. prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
  173. prefect/_internal/pydantic/utilities/model_fields.py +0 -50
  174. prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
  175. prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
  176. prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
  177. prefect/_internal/pydantic/utilities/model_validate.py +0 -75
  178. prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
  179. prefect/_internal/pydantic/utilities/model_validator.py +0 -87
  180. prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
  181. prefect/_vendor/fastapi/__init__.py +0 -25
  182. prefect/_vendor/fastapi/applications.py +0 -946
  183. prefect/_vendor/fastapi/background.py +0 -3
  184. prefect/_vendor/fastapi/concurrency.py +0 -44
  185. prefect/_vendor/fastapi/datastructures.py +0 -58
  186. prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
  187. prefect/_vendor/fastapi/dependencies/models.py +0 -64
  188. prefect/_vendor/fastapi/dependencies/utils.py +0 -877
  189. prefect/_vendor/fastapi/encoders.py +0 -177
  190. prefect/_vendor/fastapi/exception_handlers.py +0 -40
  191. prefect/_vendor/fastapi/exceptions.py +0 -46
  192. prefect/_vendor/fastapi/logger.py +0 -3
  193. prefect/_vendor/fastapi/middleware/__init__.py +0 -1
  194. prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
  195. prefect/_vendor/fastapi/middleware/cors.py +0 -3
  196. prefect/_vendor/fastapi/middleware/gzip.py +0 -3
  197. prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
  198. prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
  199. prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
  200. prefect/_vendor/fastapi/openapi/__init__.py +0 -0
  201. prefect/_vendor/fastapi/openapi/constants.py +0 -2
  202. prefect/_vendor/fastapi/openapi/docs.py +0 -203
  203. prefect/_vendor/fastapi/openapi/models.py +0 -480
  204. prefect/_vendor/fastapi/openapi/utils.py +0 -485
  205. prefect/_vendor/fastapi/param_functions.py +0 -340
  206. prefect/_vendor/fastapi/params.py +0 -453
  207. prefect/_vendor/fastapi/py.typed +0 -0
  208. prefect/_vendor/fastapi/requests.py +0 -4
  209. prefect/_vendor/fastapi/responses.py +0 -40
  210. prefect/_vendor/fastapi/routing.py +0 -1331
  211. prefect/_vendor/fastapi/security/__init__.py +0 -15
  212. prefect/_vendor/fastapi/security/api_key.py +0 -98
  213. prefect/_vendor/fastapi/security/base.py +0 -6
  214. prefect/_vendor/fastapi/security/http.py +0 -172
  215. prefect/_vendor/fastapi/security/oauth2.py +0 -227
  216. prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
  217. prefect/_vendor/fastapi/security/utils.py +0 -10
  218. prefect/_vendor/fastapi/staticfiles.py +0 -1
  219. prefect/_vendor/fastapi/templating.py +0 -3
  220. prefect/_vendor/fastapi/testclient.py +0 -1
  221. prefect/_vendor/fastapi/types.py +0 -3
  222. prefect/_vendor/fastapi/utils.py +0 -235
  223. prefect/_vendor/fastapi/websockets.py +0 -7
  224. prefect/_vendor/starlette/__init__.py +0 -1
  225. prefect/_vendor/starlette/_compat.py +0 -28
  226. prefect/_vendor/starlette/_exception_handler.py +0 -80
  227. prefect/_vendor/starlette/_utils.py +0 -88
  228. prefect/_vendor/starlette/applications.py +0 -261
  229. prefect/_vendor/starlette/authentication.py +0 -159
  230. prefect/_vendor/starlette/background.py +0 -43
  231. prefect/_vendor/starlette/concurrency.py +0 -59
  232. prefect/_vendor/starlette/config.py +0 -151
  233. prefect/_vendor/starlette/convertors.py +0 -87
  234. prefect/_vendor/starlette/datastructures.py +0 -707
  235. prefect/_vendor/starlette/endpoints.py +0 -130
  236. prefect/_vendor/starlette/exceptions.py +0 -60
  237. prefect/_vendor/starlette/formparsers.py +0 -276
  238. prefect/_vendor/starlette/middleware/__init__.py +0 -17
  239. prefect/_vendor/starlette/middleware/authentication.py +0 -52
  240. prefect/_vendor/starlette/middleware/base.py +0 -220
  241. prefect/_vendor/starlette/middleware/cors.py +0 -176
  242. prefect/_vendor/starlette/middleware/errors.py +0 -265
  243. prefect/_vendor/starlette/middleware/exceptions.py +0 -74
  244. prefect/_vendor/starlette/middleware/gzip.py +0 -113
  245. prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
  246. prefect/_vendor/starlette/middleware/sessions.py +0 -82
  247. prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
  248. prefect/_vendor/starlette/middleware/wsgi.py +0 -147
  249. prefect/_vendor/starlette/py.typed +0 -0
  250. prefect/_vendor/starlette/requests.py +0 -328
  251. prefect/_vendor/starlette/responses.py +0 -347
  252. prefect/_vendor/starlette/routing.py +0 -933
  253. prefect/_vendor/starlette/schemas.py +0 -154
  254. prefect/_vendor/starlette/staticfiles.py +0 -248
  255. prefect/_vendor/starlette/status.py +0 -199
  256. prefect/_vendor/starlette/templating.py +0 -231
  257. prefect/_vendor/starlette/testclient.py +0 -804
  258. prefect/_vendor/starlette/types.py +0 -30
  259. prefect/_vendor/starlette/websockets.py +0 -193
  260. prefect/blocks/kubernetes.py +0 -119
  261. prefect/deprecated/__init__.py +0 -0
  262. prefect/deprecated/data_documents.py +0 -350
  263. prefect/deprecated/packaging/__init__.py +0 -12
  264. prefect/deprecated/packaging/base.py +0 -96
  265. prefect/deprecated/packaging/docker.py +0 -146
  266. prefect/deprecated/packaging/file.py +0 -92
  267. prefect/deprecated/packaging/orion.py +0 -80
  268. prefect/deprecated/packaging/serializers.py +0 -171
  269. prefect/events/instrument.py +0 -135
  270. prefect/infrastructure/container.py +0 -824
  271. prefect/infrastructure/kubernetes.py +0 -920
  272. prefect/infrastructure/process.py +0 -289
  273. prefect/manifests.py +0 -20
  274. prefect/new_flow_engine.py +0 -449
  275. prefect/new_task_engine.py +0 -423
  276. prefect/pydantic/__init__.py +0 -76
  277. prefect/pydantic/main.py +0 -39
  278. prefect/software/__init__.py +0 -2
  279. prefect/software/base.py +0 -50
  280. prefect/software/conda.py +0 -199
  281. prefect/software/pip.py +0 -122
  282. prefect/software/python.py +0 -52
  283. prefect/task_server.py +0 -322
  284. prefect_client-2.20.2.dist-info/RECORD +0 -294
  285. /prefect/{_internal/pydantic/utilities → client/types}/__init__.py +0 -0
  286. /prefect/{_vendor → concurrency/v1}/__init__.py +0 -0
  287. {prefect_client-2.20.2.dist-info → prefect_client-3.0.0.dist-info}/LICENSE +0 -0
  288. {prefect_client-2.20.2.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 shutil import ignore_patterns
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
- from prefect.utilities.processutils import run_process
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, local_path: str = None, to_path: str = None, ignore_file: str = None
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
- @validator("basepath", pre=True)
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
- path: Path = Path(path).expanduser()
111
+ resolved_path: Path = Path(path).expanduser()
120
112
 
121
- if not path.is_absolute():
122
- path = basepath / path
113
+ if not resolved_path.is_absolute():
114
+ resolved_path = basepath / resolved_path
123
115
  else:
124
- path = path.resolve()
125
- if basepath not in path.parents and (basepath != path):
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 {path} is outside of the base path {basepath}."
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, local_path: str = None, to_path: str = None, ignore_file: str = None
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
- @validator("basepath")
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=..., tile="SMB server/hostname", description="SMB server/hostname."
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
- @deprecated_class(
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__)