ygg 0.1.32__py3-none-any.whl → 0.1.34__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.
- {ygg-0.1.32.dist-info → ygg-0.1.34.dist-info}/METADATA +1 -1
- {ygg-0.1.32.dist-info → ygg-0.1.34.dist-info}/RECORD +14 -13
- yggdrasil/databricks/compute/cluster.py +109 -58
- yggdrasil/databricks/compute/execution_context.py +5 -2
- yggdrasil/databricks/compute/remote.py +14 -5
- yggdrasil/databricks/sql/engine.py +295 -321
- yggdrasil/databricks/workspaces/workspace.py +12 -1
- yggdrasil/pyutils/callable_serde.py +27 -2
- yggdrasil/pyutils/expiring_dict.py +176 -0
- yggdrasil/version.py +1 -1
- {ygg-0.1.32.dist-info → ygg-0.1.34.dist-info}/WHEEL +0 -0
- {ygg-0.1.32.dist-info → ygg-0.1.34.dist-info}/entry_points.txt +0 -0
- {ygg-0.1.32.dist-info → ygg-0.1.34.dist-info}/licenses/LICENSE +0 -0
- {ygg-0.1.32.dist-info → ygg-0.1.34.dist-info}/top_level.txt +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
ygg-0.1.
|
|
1
|
+
ygg-0.1.34.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
2
2
|
yggdrasil/__init__.py,sha256=PfH7Xwt6uue6oqe6S5V8NhDJcVQClkKrBE1KXhdelZc,117
|
|
3
|
-
yggdrasil/version.py,sha256=
|
|
3
|
+
yggdrasil/version.py,sha256=cIz48TZT2Xc-LLdWHdfAlxnIA0OSZqt42ZJcukkGo6s,22
|
|
4
4
|
yggdrasil/databricks/__init__.py,sha256=skctY2c8W-hI81upx9F_PWRe5ishL3hrdiTuizgDjdw,152
|
|
5
5
|
yggdrasil/databricks/compute/__init__.py,sha256=NvdzmaJSNYY1uJthv1hHdBuNu3bD_-Z65DWnaJt9yXg,289
|
|
6
|
-
yggdrasil/databricks/compute/cluster.py,sha256=
|
|
7
|
-
yggdrasil/databricks/compute/execution_context.py,sha256=
|
|
8
|
-
yggdrasil/databricks/compute/remote.py,sha256=
|
|
6
|
+
yggdrasil/databricks/compute/cluster.py,sha256=KUyGcpEKiA5XgAbeX1iHzuhJ4pucFqch_galZwYJlnc,39599
|
|
7
|
+
yggdrasil/databricks/compute/execution_context.py,sha256=Z0EvkhdR803Kh1UOh4wR0oyyLXzAJo4Lj5CRNmxW4q4,22287
|
|
8
|
+
yggdrasil/databricks/compute/remote.py,sha256=rrqLMnzI0KvhXghtOrve3W-rudi-cTjS-8dJXKjHM3A,2266
|
|
9
9
|
yggdrasil/databricks/jobs/__init__.py,sha256=snxGSJb0M5I39v0y3IR-uEeSlZR248cQ_4DJ1sYs-h8,154
|
|
10
10
|
yggdrasil/databricks/jobs/config.py,sha256=9LGeHD04hbfy0xt8_6oobC4moKJh4_DTjZiK4Q2Tqjk,11557
|
|
11
11
|
yggdrasil/databricks/sql/__init__.py,sha256=y1n5yg-drZ8QVZbEgznsRG24kdJSnFis9l2YfYCsaCM,234
|
|
12
|
-
yggdrasil/databricks/sql/engine.py,sha256=
|
|
12
|
+
yggdrasil/databricks/sql/engine.py,sha256=weYHosCVc9CZYaVooexEphNw6W_Ex0dphuGbfA48mEI,41104
|
|
13
13
|
yggdrasil/databricks/sql/exceptions.py,sha256=Jqd_gT_VyPL8klJEHYEzpv5eHtmdY43WiQ7HZBaEqSk,53
|
|
14
14
|
yggdrasil/databricks/sql/statement_result.py,sha256=VlHXhTcvTVya_2aJ-uUfUooZF_MqQuOZ8k7g6PBDhOM,17227
|
|
15
15
|
yggdrasil/databricks/sql/types.py,sha256=5G-BM9_eOsRKEMzeDTWUsWW5g4Idvs-czVCpOCrMhdA,6412
|
|
@@ -18,7 +18,7 @@ yggdrasil/databricks/workspaces/filesytem.py,sha256=Z8JXU7_XUEbw9fpTQT1avRQKi-IA
|
|
|
18
18
|
yggdrasil/databricks/workspaces/io.py,sha256=Tdde4LaGNJNT50R11OkEYZyNacyIW9QrOXMAicAlIr4,32208
|
|
19
19
|
yggdrasil/databricks/workspaces/path.py,sha256=-XnCD9p42who3DAwnITVE1KyrZUSoXDKHA8iZi-7wk4,47743
|
|
20
20
|
yggdrasil/databricks/workspaces/path_kind.py,sha256=Xc319NysH8_6E9C0Q8nCxDHYG07_SnzyUVKHe0dNdDQ,305
|
|
21
|
-
yggdrasil/databricks/workspaces/workspace.py,sha256=
|
|
21
|
+
yggdrasil/databricks/workspaces/workspace.py,sha256=MW-BEyldROqbX9SBbDspvlys_zehJjK5YgM3sGLfW-g,23382
|
|
22
22
|
yggdrasil/dataclasses/__init__.py,sha256=6SdfIyTsoM4AuVw5TW4Q-UWXz41EyfsMcpD30cmjbSM,125
|
|
23
23
|
yggdrasil/dataclasses/dataclass.py,sha256=fKokFUnqe4CmXXGMTdF4XDWbCUl_c_-se-UD48L5s1E,6594
|
|
24
24
|
yggdrasil/libs/__init__.py,sha256=ulzk-ZkFUI2Pfo93YKtO8MBsEWtRZzLos7HAxN74R0w,168
|
|
@@ -30,8 +30,9 @@ yggdrasil/libs/extensions/__init__.py,sha256=mcXW5Li3Cbprbs4Ci-b5A0Ju0wmLcfvEiFu
|
|
|
30
30
|
yggdrasil/libs/extensions/polars_extensions.py,sha256=RTkGi8llhPJjX7x9egix7-yXWo2X24zIAPSKXV37SSA,12397
|
|
31
31
|
yggdrasil/libs/extensions/spark_extensions.py,sha256=E64n-3SFTDgMuXwWitX6vOYP9ln2lpGKb0htoBLEZgc,16745
|
|
32
32
|
yggdrasil/pyutils/__init__.py,sha256=tl-LapAc71TV7RMgf2ftKwrzr8iiLOGHeJgA3RvO93w,293
|
|
33
|
-
yggdrasil/pyutils/callable_serde.py,sha256=
|
|
33
|
+
yggdrasil/pyutils/callable_serde.py,sha256=euY7Kiy04i1tpWKuB0b2qQ1FokLC3nq0cv7PObWYUBE,21809
|
|
34
34
|
yggdrasil/pyutils/exceptions.py,sha256=ssKNm-rjhavHUOZmGA7_1Gq9tSHDrb2EFI-cnBuWgng,3388
|
|
35
|
+
yggdrasil/pyutils/expiring_dict.py,sha256=q9gb09-2EUN-jQZumUw5BXOQGYcj1wb85qKtQlciSxg,5825
|
|
35
36
|
yggdrasil/pyutils/modules.py,sha256=B7IP99YqUMW6-DIESFzBx8-09V1d0a8qrIJUDFhhL2g,11424
|
|
36
37
|
yggdrasil/pyutils/parallel.py,sha256=ubuq2m9dJzWYUyKCga4Y_9bpaeMYUrleYxdp49CHr44,6781
|
|
37
38
|
yggdrasil/pyutils/python_env.py,sha256=tuglnjdqHQjNh18qDladVoSEOjCD0RcnMEPYJ0tArOs,50985
|
|
@@ -53,8 +54,8 @@ yggdrasil/types/cast/registry.py,sha256=_zdFGmUBB7P-e_LIcJlOxMcxAkXoA-UXB6HqLMgT
|
|
|
53
54
|
yggdrasil/types/cast/spark_cast.py,sha256=_KAsl1DqmKMSfWxqhVE7gosjYdgiL1C5bDQv6eP3HtA,24926
|
|
54
55
|
yggdrasil/types/cast/spark_pandas_cast.py,sha256=BuTiWrdCANZCdD_p2MAytqm74eq-rdRXd-LGojBRrfU,5023
|
|
55
56
|
yggdrasil/types/cast/spark_polars_cast.py,sha256=btmZNHXn2NSt3fUuB4xg7coaE0RezIBdZD92H8NK0Jw,9073
|
|
56
|
-
ygg-0.1.
|
|
57
|
-
ygg-0.1.
|
|
58
|
-
ygg-0.1.
|
|
59
|
-
ygg-0.1.
|
|
60
|
-
ygg-0.1.
|
|
57
|
+
ygg-0.1.34.dist-info/METADATA,sha256=iGQcUq6tGnBBLiVo9jPak9PE-Ma8wWPxY2BsWKLGC2w,19204
|
|
58
|
+
ygg-0.1.34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
59
|
+
ygg-0.1.34.dist-info/entry_points.txt,sha256=6q-vpWG3kvw2dhctQ0LALdatoeefkN855Ev02I1dKGY,70
|
|
60
|
+
ygg-0.1.34.dist-info/top_level.txt,sha256=iBe9Kk4VIVbLpgv_p8OZUIfxgj4dgJ5wBg6vO3rigso,10
|
|
61
|
+
ygg-0.1.34.dist-info/RECORD,,
|
|
@@ -24,6 +24,7 @@ from .execution_context import ExecutionContext
|
|
|
24
24
|
from ..workspaces.workspace import WorkspaceService, Workspace
|
|
25
25
|
from ... import retry, CallableSerde
|
|
26
26
|
from ...libs.databrickslib import databricks_sdk
|
|
27
|
+
from ...pyutils.expiring_dict import ExpiringDict
|
|
27
28
|
from ...pyutils.modules import PipIndexSettings
|
|
28
29
|
from ...pyutils.python_env import PythonEnv
|
|
29
30
|
|
|
@@ -45,6 +46,31 @@ else: # pragma: no cover - runtime fallback when SDK is missing
|
|
|
45
46
|
__all__ = ["Cluster"]
|
|
46
47
|
|
|
47
48
|
|
|
49
|
+
NAME_ID_CACHE: dict[str, ExpiringDict] = {}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def set_cached_cluster_name(
|
|
53
|
+
host: str,
|
|
54
|
+
cluster_name: str,
|
|
55
|
+
cluster_id: str
|
|
56
|
+
) -> None:
|
|
57
|
+
existing = NAME_ID_CACHE.get(host)
|
|
58
|
+
|
|
59
|
+
if not existing:
|
|
60
|
+
existing = NAME_ID_CACHE[host] = ExpiringDict(default_ttl=60)
|
|
61
|
+
|
|
62
|
+
existing[cluster_name] = cluster_id
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_cached_cluster_id(
|
|
66
|
+
host: str,
|
|
67
|
+
cluster_name: str,
|
|
68
|
+
) -> str:
|
|
69
|
+
existing = NAME_ID_CACHE.get(host)
|
|
70
|
+
|
|
71
|
+
return existing.get(cluster_name) if existing else None
|
|
72
|
+
|
|
73
|
+
|
|
48
74
|
logger = logging.getLogger(__name__)
|
|
49
75
|
|
|
50
76
|
|
|
@@ -84,6 +110,7 @@ class Cluster(WorkspaceService):
|
|
|
84
110
|
|
|
85
111
|
_details: Optional["ClusterDetails"] = dataclasses.field(default=None, repr=False)
|
|
86
112
|
_details_refresh_time: float = dataclasses.field(default=0, repr=False)
|
|
113
|
+
_system_context: Optional[ExecutionContext] = None
|
|
87
114
|
|
|
88
115
|
# host → Cluster instance
|
|
89
116
|
_env_clusters: ClassVar[Dict[str, "Cluster"]] = {}
|
|
@@ -98,10 +125,11 @@ class Cluster(WorkspaceService):
|
|
|
98
125
|
"""Return the current cluster name."""
|
|
99
126
|
return self.cluster_name
|
|
100
127
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if self.
|
|
104
|
-
self.
|
|
128
|
+
@property
|
|
129
|
+
def system_context(self):
|
|
130
|
+
if self._system_context is None:
|
|
131
|
+
self._system_context = self.context(language=Language.PYTHON)
|
|
132
|
+
return self._system_context
|
|
105
133
|
|
|
106
134
|
def is_in_databricks_environment(self):
|
|
107
135
|
"""Return True when running on a Databricks runtime."""
|
|
@@ -233,9 +261,8 @@ class Cluster(WorkspaceService):
|
|
|
233
261
|
Returns:
|
|
234
262
|
The updated PythonEnv instance.
|
|
235
263
|
"""
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
version_info = m.version_info
|
|
264
|
+
m = self.system_context.remote_metadata
|
|
265
|
+
version_info = m.version_info
|
|
239
266
|
|
|
240
267
|
python_version = ".".join(str(_) for _ in version_info)
|
|
241
268
|
|
|
@@ -258,7 +285,7 @@ class Cluster(WorkspaceService):
|
|
|
258
285
|
)
|
|
259
286
|
|
|
260
287
|
return target
|
|
261
|
-
|
|
288
|
+
|
|
262
289
|
@property
|
|
263
290
|
def details(self):
|
|
264
291
|
"""Return cached cluster details, refreshing when needed."""
|
|
@@ -300,21 +327,6 @@ class Cluster(WorkspaceService):
|
|
|
300
327
|
return details.state
|
|
301
328
|
return State.UNKNOWN
|
|
302
329
|
|
|
303
|
-
def get_state(self, max_delay: float = None):
|
|
304
|
-
"""Return the cluster state with a custom refresh delay.
|
|
305
|
-
|
|
306
|
-
Args:
|
|
307
|
-
max_delay: Maximum age in seconds before refresh.
|
|
308
|
-
|
|
309
|
-
Returns:
|
|
310
|
-
The current cluster state.
|
|
311
|
-
"""
|
|
312
|
-
details = self.fresh_details(max_delay=max_delay)
|
|
313
|
-
|
|
314
|
-
if details is not None:
|
|
315
|
-
return details.state
|
|
316
|
-
return State.UNKNOWN
|
|
317
|
-
|
|
318
330
|
@property
|
|
319
331
|
def is_running(self):
|
|
320
332
|
"""Return True when the cluster is running."""
|
|
@@ -323,7 +335,10 @@ class Cluster(WorkspaceService):
|
|
|
323
335
|
@property
|
|
324
336
|
def is_pending(self):
|
|
325
337
|
"""Return True when the cluster is starting, resizing, or terminating."""
|
|
326
|
-
return self.state in
|
|
338
|
+
return self.state in (
|
|
339
|
+
State.PENDING, State.RESIZING, State.RESTARTING,
|
|
340
|
+
State.TERMINATING
|
|
341
|
+
)
|
|
327
342
|
|
|
328
343
|
@property
|
|
329
344
|
def is_error(self):
|
|
@@ -507,45 +522,51 @@ class Cluster(WorkspaceService):
|
|
|
507
522
|
):
|
|
508
523
|
pip_settings = PipIndexSettings.default_settings()
|
|
509
524
|
|
|
510
|
-
|
|
511
|
-
details
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
525
|
+
new_details = ClusterDetails(**{
|
|
526
|
+
**details.as_shallow_dict(),
|
|
527
|
+
**kwargs
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
default_tags = self.workspace.default_tags()
|
|
531
|
+
|
|
532
|
+
if new_details.custom_tags is None:
|
|
533
|
+
new_details.custom_tags = default_tags
|
|
534
|
+
elif default_tags:
|
|
535
|
+
new_tags = new_details.custom_tags.copy()
|
|
536
|
+
new_tags.update(default_tags)
|
|
515
537
|
|
|
516
|
-
|
|
517
|
-
details.custom_tags = self.workspace.default_tags()
|
|
538
|
+
new_details.custom_tags = new_tags
|
|
518
539
|
|
|
519
|
-
if
|
|
520
|
-
|
|
540
|
+
if new_details.cluster_name is None:
|
|
541
|
+
new_details.cluster_name = self.workspace.current_user.user_name
|
|
521
542
|
|
|
522
|
-
if
|
|
523
|
-
|
|
543
|
+
if new_details.spark_version is None or python_version:
|
|
544
|
+
new_details.spark_version = self.latest_spark_version(
|
|
524
545
|
photon=False, python_version=python_version
|
|
525
546
|
).key
|
|
526
547
|
|
|
527
|
-
if
|
|
528
|
-
if not
|
|
529
|
-
|
|
548
|
+
if new_details.single_user_name:
|
|
549
|
+
if not new_details.data_security_mode:
|
|
550
|
+
new_details.data_security_mode = DataSecurityMode.DATA_SECURITY_MODE_DEDICATED
|
|
530
551
|
|
|
531
|
-
if not
|
|
532
|
-
|
|
552
|
+
if not new_details.node_type_id:
|
|
553
|
+
new_details.node_type_id = "rd-fleet.xlarge"
|
|
533
554
|
|
|
534
|
-
if getattr(
|
|
535
|
-
if
|
|
536
|
-
|
|
555
|
+
if getattr(new_details, "virtual_cluster_size", None) is None and new_details.num_workers is None and new_details.autoscale is None:
|
|
556
|
+
if new_details.is_single_node is None:
|
|
557
|
+
new_details.is_single_node = True
|
|
537
558
|
|
|
538
|
-
if
|
|
539
|
-
|
|
559
|
+
if new_details.is_single_node is not None and new_details.kind is None:
|
|
560
|
+
new_details.kind = Kind.CLASSIC_PREVIEW
|
|
540
561
|
|
|
541
562
|
if pip_settings.extra_index_urls:
|
|
542
|
-
if
|
|
543
|
-
|
|
563
|
+
if new_details.spark_env_vars is None:
|
|
564
|
+
new_details.spark_env_vars = {}
|
|
544
565
|
str_urls = " ".join(pip_settings.extra_index_urls)
|
|
545
|
-
|
|
546
|
-
|
|
566
|
+
new_details.spark_env_vars["UV_EXTRA_INDEX_URL"] = new_details.spark_env_vars.get("UV_INDEX", str_urls)
|
|
567
|
+
new_details.spark_env_vars["PIP_EXTRA_INDEX_URL"] = new_details.spark_env_vars.get("PIP_EXTRA_INDEX_URL", str_urls)
|
|
547
568
|
|
|
548
|
-
return
|
|
569
|
+
return new_details
|
|
549
570
|
|
|
550
571
|
def create_or_update(
|
|
551
572
|
self,
|
|
@@ -658,7 +679,9 @@ class Cluster(WorkspaceService):
|
|
|
658
679
|
)
|
|
659
680
|
|
|
660
681
|
self.wait_for_status()
|
|
661
|
-
self.details =
|
|
682
|
+
self.details = retry(tries=4, delay=0.5, max_delay=2)(
|
|
683
|
+
self.clusters_client().edit_and_wait
|
|
684
|
+
)(**update_details)
|
|
662
685
|
|
|
663
686
|
logger.info(
|
|
664
687
|
"Updated %s",
|
|
@@ -704,6 +727,12 @@ class Cluster(WorkspaceService):
|
|
|
704
727
|
if not cluster_name and not cluster_id:
|
|
705
728
|
raise ValueError("Either name or cluster_id must be provided")
|
|
706
729
|
|
|
730
|
+
if not cluster_id:
|
|
731
|
+
cluster_id = get_cached_cluster_id(
|
|
732
|
+
host=self.workspace.safe_host,
|
|
733
|
+
cluster_name=cluster_name
|
|
734
|
+
)
|
|
735
|
+
|
|
707
736
|
if cluster_id:
|
|
708
737
|
try:
|
|
709
738
|
details = self.clusters_client().get(cluster_id=cluster_id)
|
|
@@ -716,10 +745,13 @@ class Cluster(WorkspaceService):
|
|
|
716
745
|
workspace=self.workspace, cluster_id=details.cluster_id, _details=details
|
|
717
746
|
)
|
|
718
747
|
|
|
719
|
-
cluster_name_cf = cluster_name.casefold()
|
|
720
|
-
|
|
721
748
|
for cluster in self.list_clusters():
|
|
722
|
-
if
|
|
749
|
+
if cluster_name == cluster.details.cluster_name:
|
|
750
|
+
set_cached_cluster_name(
|
|
751
|
+
host=self.workspace.safe_host,
|
|
752
|
+
cluster_name=cluster.cluster_name,
|
|
753
|
+
cluster_id=cluster.cluster_id
|
|
754
|
+
)
|
|
723
755
|
return cluster
|
|
724
756
|
|
|
725
757
|
if raise_error:
|
|
@@ -812,6 +844,7 @@ class Cluster(WorkspaceService):
|
|
|
812
844
|
env_keys: Optional[List[str]] = None,
|
|
813
845
|
timeout: Optional[dt.timedelta] = None,
|
|
814
846
|
result_tag: Optional[str] = None,
|
|
847
|
+
context: Optional[ExecutionContext] = None,
|
|
815
848
|
):
|
|
816
849
|
"""Execute a command or callable on the cluster.
|
|
817
850
|
|
|
@@ -823,11 +856,14 @@ class Cluster(WorkspaceService):
|
|
|
823
856
|
env_keys: Optional environment variable names to pass.
|
|
824
857
|
timeout: Optional timeout for execution.
|
|
825
858
|
result_tag: Optional result tag for parsing output.
|
|
859
|
+
context: ExecutionContext to run or create new one
|
|
826
860
|
|
|
827
861
|
Returns:
|
|
828
862
|
The decoded result from the execution context.
|
|
829
863
|
"""
|
|
830
|
-
|
|
864
|
+
context = self.system_context if context is None else context
|
|
865
|
+
|
|
866
|
+
return context.execute(
|
|
831
867
|
obj=obj,
|
|
832
868
|
args=args,
|
|
833
869
|
kwargs=kwargs,
|
|
@@ -848,6 +884,8 @@ class Cluster(WorkspaceService):
|
|
|
848
884
|
env_variables: Optional[Dict[str, str]] = None,
|
|
849
885
|
timeout: Optional[dt.timedelta] = None,
|
|
850
886
|
result_tag: Optional[str] = None,
|
|
887
|
+
force_local: bool = False,
|
|
888
|
+
context: Optional[ExecutionContext] = None,
|
|
851
889
|
**options
|
|
852
890
|
):
|
|
853
891
|
"""
|
|
@@ -873,16 +911,29 @@ class Cluster(WorkspaceService):
|
|
|
873
911
|
env_variables: Optional environment variables to inject.
|
|
874
912
|
timeout: Optional timeout for remote execution.
|
|
875
913
|
result_tag: Optional tag for parsing remote output.
|
|
914
|
+
force_local: force local execution
|
|
915
|
+
context: ExecutionContext to run or create new one
|
|
876
916
|
**options: Additional execution options passed through.
|
|
877
917
|
|
|
878
918
|
Returns:
|
|
879
919
|
A decorator or wrapped function that executes remotely.
|
|
880
920
|
"""
|
|
921
|
+
if force_local or self.is_in_databricks_environment():
|
|
922
|
+
# Support both @ws.remote and @ws.remote(...)
|
|
923
|
+
if _func is not None and callable(_func):
|
|
924
|
+
return _func
|
|
925
|
+
|
|
926
|
+
def identity(x):
|
|
927
|
+
return x
|
|
928
|
+
|
|
929
|
+
return identity
|
|
930
|
+
|
|
931
|
+
context = self.system_context if context is None else context
|
|
932
|
+
|
|
881
933
|
def decorator(func: Callable):
|
|
882
|
-
if
|
|
934
|
+
if force_local or self.is_in_databricks_environment():
|
|
883
935
|
return func
|
|
884
936
|
|
|
885
|
-
context = self.context(language=language or Language.PYTHON)
|
|
886
937
|
serialized = CallableSerde.from_callable(func)
|
|
887
938
|
|
|
888
939
|
@functools.wraps(func)
|
|
@@ -1109,7 +1160,7 @@ class Cluster(WorkspaceService):
|
|
|
1109
1160
|
)
|
|
1110
1161
|
|
|
1111
1162
|
with open(value, mode="rb") as f:
|
|
1112
|
-
target_path.
|
|
1163
|
+
target_path.open().write_all_bytes(f.read())
|
|
1113
1164
|
|
|
1114
1165
|
value = str(target_path)
|
|
1115
1166
|
elif "." in value and not "/" in value:
|
|
@@ -367,6 +367,8 @@ print(json.dumps(meta))"""
|
|
|
367
367
|
args=args,
|
|
368
368
|
kwargs=kwargs,
|
|
369
369
|
result_tag=result_tag,
|
|
370
|
+
env_keys=env_keys,
|
|
371
|
+
env_variables=env_variables
|
|
370
372
|
) if not command else command
|
|
371
373
|
|
|
372
374
|
raw_result = self.execute_command(
|
|
@@ -382,8 +384,9 @@ print(json.dumps(meta))"""
|
|
|
382
384
|
module_name = module_name.group(1) if module_name else None
|
|
383
385
|
module_name = module_name.split(".")[0]
|
|
384
386
|
|
|
385
|
-
if module_name:
|
|
387
|
+
if module_name and "yggdrasil" not in module_name:
|
|
386
388
|
self.close()
|
|
389
|
+
|
|
387
390
|
self.cluster.install_libraries(
|
|
388
391
|
libraries=[module_name],
|
|
389
392
|
raise_error=True,
|
|
@@ -442,7 +445,7 @@ print(json.dumps(meta))"""
|
|
|
442
445
|
module_name = module_name.group(1) if module_name else None
|
|
443
446
|
module_name = module_name.split(".")[0]
|
|
444
447
|
|
|
445
|
-
if module_name:
|
|
448
|
+
if module_name and "yggdrasil" not in module_name:
|
|
446
449
|
self.close()
|
|
447
450
|
self.cluster.install_libraries(
|
|
448
451
|
libraries=[module_name],
|
|
@@ -14,6 +14,12 @@ if TYPE_CHECKING:
|
|
|
14
14
|
|
|
15
15
|
from ..workspaces.workspace import Workspace
|
|
16
16
|
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"databricks_remote_compute"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
17
23
|
ReturnType = TypeVar("ReturnType")
|
|
18
24
|
|
|
19
25
|
logger = logging.getLogger(__name__)
|
|
@@ -26,6 +32,7 @@ def databricks_remote_compute(
|
|
|
26
32
|
cluster: Optional["Cluster"] = None,
|
|
27
33
|
timeout: Optional[dt.timedelta] = None,
|
|
28
34
|
env_keys: Optional[List[str]] = None,
|
|
35
|
+
force_local: bool = False,
|
|
29
36
|
**options
|
|
30
37
|
) -> Callable[[Callable[..., ReturnType]], Callable[..., ReturnType]]:
|
|
31
38
|
"""Return a decorator that executes functions on a remote cluster.
|
|
@@ -37,11 +44,18 @@ def databricks_remote_compute(
|
|
|
37
44
|
cluster: Pre-configured Cluster instance to reuse.
|
|
38
45
|
timeout: Optional execution timeout for remote calls.
|
|
39
46
|
env_keys: Optional environment variable names to forward.
|
|
47
|
+
force_local: Force local execution
|
|
40
48
|
**options: Extra options forwarded to the execution decorator.
|
|
41
49
|
|
|
42
50
|
Returns:
|
|
43
51
|
A decorator that runs functions on the resolved Databricks cluster.
|
|
44
52
|
"""
|
|
53
|
+
if force_local or Workspace.is_in_databricks_environment():
|
|
54
|
+
def identity(x):
|
|
55
|
+
return x
|
|
56
|
+
|
|
57
|
+
return identity
|
|
58
|
+
|
|
45
59
|
if isinstance(workspace, str):
|
|
46
60
|
workspace = Workspace(host=workspace)
|
|
47
61
|
|
|
@@ -62,8 +76,3 @@ def databricks_remote_compute(
|
|
|
62
76
|
timeout=timeout,
|
|
63
77
|
**options
|
|
64
78
|
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
__all__ = [
|
|
68
|
-
"databricks_remote_compute",
|
|
69
|
-
]
|