ygg 0.1.31__tar.gz → 0.1.32__tar.gz

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 (71) hide show
  1. {ygg-0.1.31 → ygg-0.1.32}/PKG-INFO +1 -1
  2. {ygg-0.1.31 → ygg-0.1.32}/pyproject.toml +1 -1
  3. {ygg-0.1.31 → ygg-0.1.32}/src/ygg.egg-info/PKG-INFO +1 -1
  4. {ygg-0.1.31 → ygg-0.1.32}/src/ygg.egg-info/SOURCES.txt +1 -0
  5. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/__init__.py +2 -0
  6. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/__init__.py +2 -0
  7. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/compute/__init__.py +2 -0
  8. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/compute/cluster.py +241 -2
  9. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/compute/execution_context.py +100 -11
  10. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/compute/remote.py +16 -0
  11. ygg-0.1.32/src/yggdrasil/databricks/jobs/__init__.py +5 -0
  12. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/jobs/config.py +29 -4
  13. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/sql/__init__.py +2 -0
  14. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/sql/engine.py +217 -36
  15. ygg-0.1.32/src/yggdrasil/databricks/sql/exceptions.py +1 -0
  16. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/sql/statement_result.py +147 -0
  17. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/sql/types.py +33 -1
  18. ygg-0.1.32/src/yggdrasil/databricks/workspaces/__init__.py +5 -0
  19. ygg-0.1.32/src/yggdrasil/databricks/workspaces/filesytem.py +344 -0
  20. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/workspaces/io.py +387 -9
  21. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/workspaces/path.py +297 -2
  22. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/workspaces/path_kind.py +3 -0
  23. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/databricks/workspaces/workspace.py +202 -5
  24. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/dataclasses/__init__.py +2 -0
  25. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/dataclasses/dataclass.py +42 -1
  26. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/libs/__init__.py +2 -0
  27. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/libs/databrickslib.py +9 -0
  28. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/libs/extensions/__init__.py +2 -0
  29. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/libs/extensions/polars_extensions.py +72 -0
  30. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/libs/extensions/spark_extensions.py +116 -0
  31. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/libs/pandaslib.py +7 -0
  32. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/libs/polarslib.py +7 -0
  33. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/libs/sparklib.py +41 -0
  34. ygg-0.1.32/src/yggdrasil/pyutils/__init__.py +8 -0
  35. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/pyutils/callable_serde.py +106 -0
  36. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/pyutils/exceptions.py +16 -0
  37. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/pyutils/modules.py +44 -1
  38. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/pyutils/parallel.py +29 -0
  39. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/pyutils/python_env.py +301 -0
  40. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/pyutils/retry.py +57 -0
  41. ygg-0.1.32/src/yggdrasil/requests/__init__.py +5 -0
  42. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/requests/msal.py +124 -3
  43. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/requests/session.py +18 -0
  44. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/__init__.py +2 -0
  45. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/__init__.py +2 -1
  46. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/arrow_cast.py +123 -1
  47. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/cast_options.py +119 -1
  48. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/pandas_cast.py +29 -0
  49. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/polars_cast.py +47 -0
  50. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/polars_pandas_cast.py +29 -0
  51. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/registry.py +176 -0
  52. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/spark_cast.py +76 -0
  53. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/spark_pandas_cast.py +29 -0
  54. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/cast/spark_polars_cast.py +28 -0
  55. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/libs.py +2 -0
  56. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/python_arrow.py +191 -0
  57. {ygg-0.1.31 → ygg-0.1.32}/src/yggdrasil/types/python_defaults.py +73 -0
  58. ygg-0.1.32/src/yggdrasil/version.py +1 -0
  59. ygg-0.1.31/src/yggdrasil/databricks/jobs/__init__.py +0 -0
  60. ygg-0.1.31/src/yggdrasil/databricks/sql/exceptions.py +0 -0
  61. ygg-0.1.31/src/yggdrasil/databricks/workspaces/__init__.py +0 -4
  62. ygg-0.1.31/src/yggdrasil/databricks/workspaces/filesytem.py +0 -161
  63. ygg-0.1.31/src/yggdrasil/pyutils/__init__.py +0 -4
  64. ygg-0.1.31/src/yggdrasil/requests/__init__.py +0 -1
  65. {ygg-0.1.31 → ygg-0.1.32}/LICENSE +0 -0
  66. {ygg-0.1.31 → ygg-0.1.32}/README.md +0 -0
  67. {ygg-0.1.31 → ygg-0.1.32}/setup.cfg +0 -0
  68. {ygg-0.1.31 → ygg-0.1.32}/src/ygg.egg-info/dependency_links.txt +0 -0
  69. {ygg-0.1.31 → ygg-0.1.32}/src/ygg.egg-info/entry_points.txt +0 -0
  70. {ygg-0.1.31 → ygg-0.1.32}/src/ygg.egg-info/requires.txt +0 -0
  71. {ygg-0.1.31 → ygg-0.1.32}/src/ygg.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ygg
3
- Version: 0.1.31
3
+ Version: 0.1.32
4
4
  Summary: Type-friendly utilities for moving data between Python objects, Arrow, Polars, Pandas, Spark, and Databricks
5
5
  Author: Yggdrasil contributors
6
6
  License: Apache License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ygg"
7
- version = "0.1.31"
7
+ version = "0.1.32"
8
8
  description = "Type-friendly utilities for moving data between Python objects, Arrow, Polars, Pandas, Spark, and Databricks"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  license = { file = "LICENSE" }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ygg
3
- Version: 0.1.31
3
+ Version: 0.1.32
4
4
  Summary: Type-friendly utilities for moving data between Python objects, Arrow, Polars, Pandas, Spark, and Databricks
5
5
  Author: Yggdrasil contributors
6
6
  License: Apache License
@@ -8,6 +8,7 @@ src/ygg.egg-info/entry_points.txt
8
8
  src/ygg.egg-info/requires.txt
9
9
  src/ygg.egg-info/top_level.txt
10
10
  src/yggdrasil/__init__.py
11
+ src/yggdrasil/version.py
11
12
  src/yggdrasil/databricks/__init__.py
12
13
  src/yggdrasil/databricks/compute/__init__.py
13
14
  src/yggdrasil/databricks/compute/cluster.py
@@ -1,3 +1,5 @@
1
+ from .version import *
1
2
  from .dataclasses import yggdataclass
2
3
  from .types import convert
3
4
  from .pyutils import *
5
+
@@ -1,3 +1,5 @@
1
+ """Databricks integrations and helpers for Yggdrasil."""
2
+
1
3
  from .workspaces import *
2
4
  from .compute import *
3
5
  from .sql import *
@@ -1,3 +1,5 @@
1
+ """Compute helpers for Databricks clusters and remote execution."""
2
+
1
3
  __all__ = [
2
4
  "databricks_remote_compute",
3
5
  "Cluster",
@@ -90,17 +90,21 @@ class Cluster(WorkspaceService):
90
90
 
91
91
  @property
92
92
  def id(self):
93
+ """Return the current cluster id."""
93
94
  return self.cluster_id
94
95
 
95
96
  @property
96
97
  def name(self) -> str:
98
+ """Return the current cluster name."""
97
99
  return self.cluster_name
98
100
 
99
101
  def __post_init__(self):
102
+ """Initialize cached details after dataclass construction."""
100
103
  if self._details is not None:
101
104
  self.details = self._details
102
105
 
103
106
  def is_in_databricks_environment(self):
107
+ """Return True when running on a Databricks runtime."""
104
108
  return self.workspace.is_in_databricks_environment()
105
109
 
106
110
  @classmethod
@@ -114,6 +118,20 @@ class Cluster(WorkspaceService):
114
118
  libraries: Optional[list[str]] = None,
115
119
  **kwargs
116
120
  ) -> "Cluster":
121
+ """Create or reuse a cluster that mirrors the current Python environment.
122
+
123
+ Args:
124
+ workspace: Workspace to use for the cluster.
125
+ cluster_id: Optional cluster id to reuse.
126
+ cluster_name: Optional cluster name to reuse.
127
+ single_user_name: Optional user name for single-user clusters.
128
+ runtime_engine: Optional Databricks runtime engine.
129
+ libraries: Optional list of libraries to install.
130
+ **kwargs: Additional cluster specification overrides.
131
+
132
+ Returns:
133
+ A Cluster instance configured for the current environment.
134
+ """
117
135
  if workspace is None:
118
136
  workspace = Workspace() # your default, whatever it is
119
137
 
@@ -146,6 +164,20 @@ class Cluster(WorkspaceService):
146
164
  libraries: Optional[list[str]] = None,
147
165
  **kwargs
148
166
  ) -> "Cluster":
167
+ """Create/update a cluster to match the local Python environment.
168
+
169
+ Args:
170
+ source: Optional PythonEnv to mirror (defaults to current).
171
+ cluster_id: Optional cluster id to update.
172
+ cluster_name: Optional cluster name to update.
173
+ single_user_name: Optional single user name for the cluster.
174
+ runtime_engine: Optional runtime engine selection.
175
+ libraries: Optional list of libraries to install.
176
+ **kwargs: Additional cluster specification overrides.
177
+
178
+ Returns:
179
+ A Cluster instance configured with the local environment.
180
+ """
149
181
  if source is None:
150
182
  source = PythonEnv.get_current()
151
183
 
@@ -192,6 +224,15 @@ class Cluster(WorkspaceService):
192
224
  name: Optional[str] = None,
193
225
  target: PythonEnv | str | None = None,
194
226
  ):
227
+ """Update or create a local PythonEnv based on remote metadata.
228
+
229
+ Args:
230
+ name: Optional name for the local PythonEnv.
231
+ target: Existing PythonEnv or name to update.
232
+
233
+ Returns:
234
+ The updated PythonEnv instance.
235
+ """
195
236
  with self.context() as c:
196
237
  m = c.remote_metadata
197
238
  version_info = m.version_info
@@ -220,11 +261,20 @@ class Cluster(WorkspaceService):
220
261
 
221
262
  @property
222
263
  def details(self):
264
+ """Return cached cluster details, refreshing when needed."""
223
265
  if self._details is None and self.cluster_id is not None:
224
266
  self.details = self.clusters_client().get(cluster_id=self.cluster_id)
225
267
  return self._details
226
268
 
227
269
  def fresh_details(self, max_delay: float | None = None):
270
+ """Refresh cluster details if older than ``max_delay`` seconds.
271
+
272
+ Args:
273
+ max_delay: Maximum age in seconds before refresh.
274
+
275
+ Returns:
276
+ The latest ClusterDetails object, if available.
277
+ """
228
278
  max_delay = max_delay or 0
229
279
  delay = time.time() - self._details_refresh_time
230
280
 
@@ -234,6 +284,7 @@ class Cluster(WorkspaceService):
234
284
 
235
285
  @details.setter
236
286
  def details(self, value: "ClusterDetails"):
287
+ """Cache cluster details and update identifiers."""
237
288
  self._details_refresh_time = time.time()
238
289
  self._details = value
239
290
 
@@ -242,6 +293,7 @@ class Cluster(WorkspaceService):
242
293
 
243
294
  @property
244
295
  def state(self):
296
+ """Return the current cluster state."""
245
297
  details = self.fresh_details(max_delay=10)
246
298
 
247
299
  if details is not None:
@@ -249,6 +301,14 @@ class Cluster(WorkspaceService):
249
301
  return State.UNKNOWN
250
302
 
251
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
+ """
252
312
  details = self.fresh_details(max_delay=max_delay)
253
313
 
254
314
  if details is not None:
@@ -257,17 +317,21 @@ class Cluster(WorkspaceService):
257
317
 
258
318
  @property
259
319
  def is_running(self):
320
+ """Return True when the cluster is running."""
260
321
  return self.state == State.RUNNING
261
322
 
262
323
  @property
263
324
  def is_pending(self):
325
+ """Return True when the cluster is starting, resizing, or terminating."""
264
326
  return self.state in (State.PENDING, State.RESIZING, State.RESTARTING, State.TERMINATING)
265
327
 
266
328
  @property
267
329
  def is_error(self):
330
+ """Return True when the cluster is in an error state."""
268
331
  return self.state == State.ERROR
269
332
 
270
333
  def raise_for_status(self):
334
+ """Raise a DatabricksError if the cluster is in an error state."""
271
335
  if self.is_error:
272
336
  raise DatabricksError("Error in %s" % self)
273
337
 
@@ -280,6 +344,17 @@ class Cluster(WorkspaceService):
280
344
  backoff: int = 2,
281
345
  max_sleep_time: float = 15
282
346
  ):
347
+ """Wait for the cluster to exit pending states.
348
+
349
+ Args:
350
+ tick: Initial sleep interval in seconds.
351
+ timeout: Max seconds to wait before timing out.
352
+ backoff: Backoff multiplier for the sleep interval.
353
+ max_sleep_time: Maximum sleep interval in seconds.
354
+
355
+ Returns:
356
+ The current Cluster instance.
357
+ """
283
358
  start = time.time()
284
359
  sleep_time = tick
285
360
 
@@ -297,6 +372,7 @@ class Cluster(WorkspaceService):
297
372
 
298
373
  @property
299
374
  def spark_version(self) -> str:
375
+ """Return the cluster Spark version string."""
300
376
  d = self.details
301
377
  if d is None:
302
378
  return None
@@ -304,6 +380,7 @@ class Cluster(WorkspaceService):
304
380
 
305
381
  @property
306
382
  def runtime_version(self):
383
+ """Return the Databricks runtime major/minor version string."""
307
384
  # Extract "major.minor" from strings like "17.3.x-scala2.13-ml-gpu"
308
385
  v = self.spark_version
309
386
 
@@ -331,6 +408,7 @@ class Cluster(WorkspaceService):
331
408
  # Internal helpers
332
409
  # ------------------------------------------------------------------ #
333
410
  def clusters_client(self) -> "ClustersAPI":
411
+ """Return the Databricks clusters API client."""
334
412
  return self.workspace.sdk().clusters
335
413
 
336
414
  def spark_versions(
@@ -338,6 +416,15 @@ class Cluster(WorkspaceService):
338
416
  photon: Optional[bool] = None,
339
417
  python_version: Optional[Union[str, tuple[int, ...]]] = None,
340
418
  ):
419
+ """List supported Spark runtimes filtered by photon and python version.
420
+
421
+ Args:
422
+ photon: If set, filter by Photon (True) or non-Photon (False).
423
+ python_version: Optional Python version filter (string or tuple).
424
+
425
+ Returns:
426
+ A list of SparkVersion entries matching the filters.
427
+ """
341
428
  all_versions = self.clusters_client().spark_versions().versions
342
429
 
343
430
  if not all_versions:
@@ -387,6 +474,15 @@ class Cluster(WorkspaceService):
387
474
  photon: Optional[bool] = None,
388
475
  python_version: Optional[Union[str, tuple[int, ...]]] = None,
389
476
  ):
477
+ """Return the latest Spark version that matches requested filters.
478
+
479
+ Args:
480
+ photon: If set, filter by Photon (True) or non-Photon (False).
481
+ python_version: Optional Python version filter (string or tuple).
482
+
483
+ Returns:
484
+ The latest SparkVersion matching the filters.
485
+ """
390
486
  versions = self.spark_versions(photon=photon, python_version=python_version)
391
487
 
392
488
  max_version: SparkVersion = None
@@ -458,6 +554,17 @@ class Cluster(WorkspaceService):
458
554
  libraries: Optional[List[Union[str, "Library"]]] = None,
459
555
  **cluster_spec: Any
460
556
  ):
557
+ """Create a new cluster or update an existing one.
558
+
559
+ Args:
560
+ cluster_id: Optional cluster id to update.
561
+ cluster_name: Optional cluster name to update or create.
562
+ libraries: Optional libraries to install.
563
+ **cluster_spec: Cluster specification overrides.
564
+
565
+ Returns:
566
+ A Cluster instance pointing at the created/updated cluster.
567
+ """
461
568
  found = self.find_cluster(
462
569
  cluster_id=cluster_id or self.cluster_id,
463
570
  cluster_name=cluster_name or self.cluster_name,
@@ -482,6 +589,15 @@ class Cluster(WorkspaceService):
482
589
  libraries: Optional[List[Union[str, "Library"]]] = None,
483
590
  **cluster_spec: Any
484
591
  ) -> str:
592
+ """Create a new cluster and optionally install libraries.
593
+
594
+ Args:
595
+ libraries: Optional list of libraries to install after creation.
596
+ **cluster_spec: Cluster specification overrides.
597
+
598
+ Returns:
599
+ The current Cluster instance.
600
+ """
485
601
  cluster_spec["autotermination_minutes"] = int(cluster_spec.get("autotermination_minutes", 30))
486
602
  update_details = self._check_details(details=ClusterDetails(), **cluster_spec)
487
603
  update_details = {
@@ -512,6 +628,15 @@ class Cluster(WorkspaceService):
512
628
  libraries: Optional[List[Union[str, "Library"]]] = None,
513
629
  **cluster_spec: Any
514
630
  ) -> "Cluster":
631
+ """Update cluster configuration and optionally install libraries.
632
+
633
+ Args:
634
+ libraries: Optional libraries to install.
635
+ **cluster_spec: Cluster specification overrides.
636
+
637
+ Returns:
638
+ The updated Cluster instance.
639
+ """
515
640
  self.install_libraries(libraries=libraries, wait_timeout=None, raise_error=False)
516
641
 
517
642
  existing_details = {
@@ -532,6 +657,7 @@ class Cluster(WorkspaceService):
532
657
  self, update_details
533
658
  )
534
659
 
660
+ self.wait_for_status()
535
661
  self.details = self.clusters_client().edit_and_wait(**update_details)
536
662
 
537
663
  logger.info(
@@ -542,7 +668,11 @@ class Cluster(WorkspaceService):
542
668
  return self
543
669
 
544
670
  def list_clusters(self) -> Iterator["Cluster"]:
545
- """Iterate clusters, yielding helpers annotated with metadata."""
671
+ """Iterate clusters, yielding helpers annotated with metadata.
672
+
673
+ Returns:
674
+ An iterator of Cluster helpers for each cluster.
675
+ """
546
676
 
547
677
  for details in self.clusters_client().list():
548
678
  details: ClusterDetails = details
@@ -561,7 +691,16 @@ class Cluster(WorkspaceService):
561
691
  cluster_name: Optional[str] = None,
562
692
  raise_error: Optional[bool] = None
563
693
  ) -> Optional["Cluster"]:
564
- """Find a cluster by name or id and return a populated helper."""
694
+ """Find a cluster by name or id and return a populated helper.
695
+
696
+ Args:
697
+ cluster_id: Optional cluster id to look up.
698
+ cluster_name: Optional cluster name to look up.
699
+ raise_error: Whether to raise if not found.
700
+
701
+ Returns:
702
+ A Cluster instance if found, otherwise None.
703
+ """
565
704
  if not cluster_name and not cluster_id:
566
705
  raise ValueError("Either name or cluster_id must be provided")
567
706
 
@@ -590,11 +729,21 @@ class Cluster(WorkspaceService):
590
729
  def ensure_running(
591
730
  self,
592
731
  ) -> "Cluster":
732
+ """Ensure the cluster is running.
733
+
734
+ Returns:
735
+ The current Cluster instance.
736
+ """
593
737
  return self.start()
594
738
 
595
739
  def start(
596
740
  self,
597
741
  ) -> "Cluster":
742
+ """Start the cluster if it is not already running.
743
+
744
+ Returns:
745
+ The current Cluster instance.
746
+ """
598
747
  self.wait_for_status()
599
748
 
600
749
  if not self.is_running:
@@ -608,6 +757,11 @@ class Cluster(WorkspaceService):
608
757
  def restart(
609
758
  self,
610
759
  ):
760
+ """Restart the cluster, waiting for libraries to install.
761
+
762
+ Returns:
763
+ The current Cluster instance.
764
+ """
611
765
  self.wait_for_status()
612
766
 
613
767
  if self.is_running:
@@ -620,6 +774,11 @@ class Cluster(WorkspaceService):
620
774
  def delete(
621
775
  self
622
776
  ):
777
+ """Delete the cluster.
778
+
779
+ Returns:
780
+ The SDK delete response.
781
+ """
623
782
  logger.info("Deleting %s", self)
624
783
  return self.clusters_client().delete(cluster_id=self.cluster_id)
625
784
 
@@ -628,6 +787,15 @@ class Cluster(WorkspaceService):
628
787
  language: Optional["Language"] = None,
629
788
  context_id: Optional[str] = None
630
789
  ) -> ExecutionContext:
790
+ """Create a command execution context for this cluster.
791
+
792
+ Args:
793
+ language: Optional language for the execution context.
794
+ context_id: Optional existing context id to reuse.
795
+
796
+ Returns:
797
+ An ExecutionContext instance.
798
+ """
631
799
  return ExecutionContext(
632
800
  cluster=self,
633
801
  language=language,
@@ -645,6 +813,20 @@ class Cluster(WorkspaceService):
645
813
  timeout: Optional[dt.timedelta] = None,
646
814
  result_tag: Optional[str] = None,
647
815
  ):
816
+ """Execute a command or callable on the cluster.
817
+
818
+ Args:
819
+ obj: Command string or callable to execute.
820
+ language: Optional language for command execution.
821
+ args: Optional positional arguments for the callable.
822
+ kwargs: Optional keyword arguments for the callable.
823
+ env_keys: Optional environment variable names to pass.
824
+ timeout: Optional timeout for execution.
825
+ result_tag: Optional result tag for parsing output.
826
+
827
+ Returns:
828
+ The decoded result from the execution context.
829
+ """
648
830
  return self.context(language=language).execute(
649
831
  obj=obj,
650
832
  args=args,
@@ -683,6 +865,18 @@ class Cluster(WorkspaceService):
683
865
 
684
866
  @ws.remote
685
867
  def h(z): ...
868
+
869
+ Args:
870
+ _func: Optional function when used as ``@ws.remote``.
871
+ language: Optional execution language override.
872
+ env_keys: Optional environment variable names to forward.
873
+ env_variables: Optional environment variables to inject.
874
+ timeout: Optional timeout for remote execution.
875
+ result_tag: Optional tag for parsing remote output.
876
+ **options: Additional execution options passed through.
877
+
878
+ Returns:
879
+ A decorator or wrapped function that executes remotely.
686
880
  """
687
881
  def decorator(func: Callable):
688
882
  if os.getenv("DATABRICKS_RUNTIME_VERSION") is not None:
@@ -723,6 +917,18 @@ class Cluster(WorkspaceService):
723
917
  raise_error: bool = True,
724
918
  restart: bool = True,
725
919
  ) -> "Cluster":
920
+ """Install libraries on the cluster and optionally wait for completion.
921
+
922
+ Args:
923
+ libraries: Libraries or package names to install.
924
+ wait_timeout: Optional timeout for installation.
925
+ pip_settings: Optional pip index settings.
926
+ raise_error: Whether to raise on install failure.
927
+ restart: Whether to restart the cluster after installation.
928
+
929
+ Returns:
930
+ The current Cluster instance.
931
+ """
726
932
  if not libraries:
727
933
  return self
728
934
 
@@ -752,6 +958,11 @@ class Cluster(WorkspaceService):
752
958
  return self
753
959
 
754
960
  def installed_library_statuses(self):
961
+ """Return current library install statuses for the cluster.
962
+
963
+ Returns:
964
+ An iterator of library install status objects.
965
+ """
755
966
  return self.workspace.sdk().libraries.cluster_status(cluster_id=self.cluster_id)
756
967
 
757
968
  def uninstall_libraries(
@@ -760,6 +971,16 @@ class Cluster(WorkspaceService):
760
971
  libraries: Optional[list["Library"]] = None,
761
972
  restart: bool = True
762
973
  ):
974
+ """Uninstall libraries from the cluster and optionally restart.
975
+
976
+ Args:
977
+ pypi_packages: Optional list of PyPI package names to uninstall.
978
+ libraries: Optional list of Library objects to uninstall.
979
+ restart: Whether to restart the cluster afterward.
980
+
981
+ Returns:
982
+ The current Cluster instance.
983
+ """
763
984
  if libraries is None:
764
985
  to_remove = [
765
986
  lib.library
@@ -805,6 +1026,16 @@ class Cluster(WorkspaceService):
805
1026
  pip_settings: Optional[PipIndexSettings] = None,
806
1027
  raise_error: bool = True,
807
1028
  ):
1029
+ """Wait for library installations to finish on the cluster.
1030
+
1031
+ Args:
1032
+ timeout: Maximum time to wait for installs.
1033
+ pip_settings: Optional pip index settings.
1034
+ raise_error: Whether to raise on failures.
1035
+
1036
+ Returns:
1037
+ The current Cluster instance.
1038
+ """
808
1039
  if not self.is_running:
809
1040
  return self
810
1041
 
@@ -851,6 +1082,14 @@ class Cluster(WorkspaceService):
851
1082
  self,
852
1083
  libraries: str | ModuleType | List[str | ModuleType],
853
1084
  ):
1085
+ """Upload local libraries to the cluster's site-packages.
1086
+
1087
+ Args:
1088
+ libraries: Library path, name, module, or iterable of these.
1089
+
1090
+ Returns:
1091
+ The uploaded library argument(s).
1092
+ """
854
1093
  return self.context().install_temporary_libraries(libraries=libraries)
855
1094
 
856
1095
  def _check_library(