ygg 0.1.38__py3-none-any.whl → 0.1.41__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ygg
3
- Version: 0.1.38
3
+ Version: 0.1.41
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
@@ -1,9 +1,9 @@
1
- ygg-0.1.38.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
1
+ ygg-0.1.41.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
2
2
  yggdrasil/__init__.py,sha256=PfH7Xwt6uue6oqe6S5V8NhDJcVQClkKrBE1KXhdelZc,117
3
- yggdrasil/version.py,sha256=pPo3-5ffVm5NbQms9PN259Sjq7R-Q9UY4HYJ8M2iom4,22
3
+ yggdrasil/version.py,sha256=MW_v7YHPKwbcPR_PtCE3ALJ0csFwgMewFF071yAYGCE,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=mnNzjCx7X3iK22oZ7K3pqot0AXq9JTdg97kT61j2_UU,40729
6
+ yggdrasil/databricks/compute/cluster.py,sha256=Ejc3VlS56QzyjFX1-wNXHC4BNc2MpDRfFFafVxPF8rE,40968
7
7
  yggdrasil/databricks/compute/execution_context.py,sha256=nxrNXoarq_JAB-Cpj0udHhq2jx-DmMbRWJdAezLrPis,22347
8
8
  yggdrasil/databricks/compute/remote.py,sha256=nEN_Fr1Ouul_iKOf4B5QjEGscYAcl7nHjGsl2toRzrU,2874
9
9
  yggdrasil/databricks/jobs/__init__.py,sha256=snxGSJb0M5I39v0y3IR-uEeSlZR248cQ_4DJ1sYs-h8,154
@@ -11,7 +11,7 @@ yggdrasil/databricks/jobs/config.py,sha256=9LGeHD04hbfy0xt8_6oobC4moKJh4_DTjZiK4
11
11
  yggdrasil/databricks/sql/__init__.py,sha256=y1n5yg-drZ8QVZbEgznsRG24kdJSnFis9l2YfYCsaCM,234
12
12
  yggdrasil/databricks/sql/engine.py,sha256=Azx3gKtWOMy3D9I2FhkLmpthZPWAJZ9iZkaDivmt_0s,41002
13
13
  yggdrasil/databricks/sql/exceptions.py,sha256=Jqd_gT_VyPL8klJEHYEzpv5eHtmdY43WiQ7HZBaEqSk,53
14
- yggdrasil/databricks/sql/statement_result.py,sha256=tik53oB7Eq6nA4Unv8qH6fe9RJJO9HcumI5BAkW3omA,16684
14
+ yggdrasil/databricks/sql/statement_result.py,sha256=_mBolHae0AASfe1Tlld1KTXs-K4-oy9dniHDyR2ILYc,16736
15
15
  yggdrasil/databricks/sql/types.py,sha256=5G-BM9_eOsRKEMzeDTWUsWW5g4Idvs-czVCpOCrMhdA,6412
16
16
  yggdrasil/databricks/workspaces/__init__.py,sha256=Ti1I99JTC3koYJaCy8WYvkAox4KdcuMRk8b2rHroWCY,133
17
17
  yggdrasil/databricks/workspaces/filesytem.py,sha256=Z8JXU7_XUEbw9fpTQT1avRQKi-IAP2KemXBMPkUoY4w,9805
@@ -30,7 +30,7 @@ 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=euY7Kiy04i1tpWKuB0b2qQ1FokLC3nq0cv7PObWYUBE,21809
33
+ yggdrasil/pyutils/callable_serde.py,sha256=FtbY2PUBHwDe2IyX28gLJwQYjtrvhvqtTSIIBc5x-dk,23538
34
34
  yggdrasil/pyutils/equality.py,sha256=Xyf8D1dLUCm3spDEir8Zyj7O4US_fBJwEylJCfJ9slI,3080
35
35
  yggdrasil/pyutils/exceptions.py,sha256=ssKNm-rjhavHUOZmGA7_1Gq9tSHDrb2EFI-cnBuWgng,3388
36
36
  yggdrasil/pyutils/expiring_dict.py,sha256=q9gb09-2EUN-jQZumUw5BXOQGYcj1wb85qKtQlciSxg,5825
@@ -55,8 +55,8 @@ yggdrasil/types/cast/registry.py,sha256=_zdFGmUBB7P-e_LIcJlOxMcxAkXoA-UXB6HqLMgT
55
55
  yggdrasil/types/cast/spark_cast.py,sha256=_KAsl1DqmKMSfWxqhVE7gosjYdgiL1C5bDQv6eP3HtA,24926
56
56
  yggdrasil/types/cast/spark_pandas_cast.py,sha256=BuTiWrdCANZCdD_p2MAytqm74eq-rdRXd-LGojBRrfU,5023
57
57
  yggdrasil/types/cast/spark_polars_cast.py,sha256=btmZNHXn2NSt3fUuB4xg7coaE0RezIBdZD92H8NK0Jw,9073
58
- ygg-0.1.38.dist-info/METADATA,sha256=2G6ZcCvdN5TLyP9Z7z3GHQio7xjzBCd-ZEOO2qnL2Yc,19204
59
- ygg-0.1.38.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
60
- ygg-0.1.38.dist-info/entry_points.txt,sha256=6q-vpWG3kvw2dhctQ0LALdatoeefkN855Ev02I1dKGY,70
61
- ygg-0.1.38.dist-info/top_level.txt,sha256=iBe9Kk4VIVbLpgv_p8OZUIfxgj4dgJ5wBg6vO3rigso,10
62
- ygg-0.1.38.dist-info/RECORD,,
58
+ ygg-0.1.41.dist-info/METADATA,sha256=EYXc8625quuP-JkcUD5FIK-5AmgYMddSWj2t4mnN2bg,19204
59
+ ygg-0.1.41.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
60
+ ygg-0.1.41.dist-info/entry_points.txt,sha256=6q-vpWG3kvw2dhctQ0LALdatoeefkN855Ev02I1dKGY,70
61
+ ygg-0.1.41.dist-info/top_level.txt,sha256=iBe9Kk4VIVbLpgv_p8OZUIfxgj4dgJ5wBg6vO3rigso,10
62
+ ygg-0.1.41.dist-info/RECORD,,
@@ -667,6 +667,8 @@ class Cluster(WorkspaceService):
667
667
  Returns:
668
668
  The updated Cluster instance.
669
669
  """
670
+ self.install_libraries(libraries=libraries, wait_timeout=None, raise_error=False)
671
+
670
672
  existing_details = {
671
673
  k: v
672
674
  for k, v in self.details.as_shallow_dict().items()
@@ -699,16 +701,20 @@ class Cluster(WorkspaceService):
699
701
  )
700
702
 
701
703
  self.wait_for_status()
702
- self.details = self.clusters_client().edit(**update_details)
703
- self.wait_for_status()
704
+ try:
705
+ self.details = self.clusters_client().edit_and_wait(**update_details)
706
+ except Exception as e:
707
+ if self.state == State.TERMINATED:
708
+ self.start()
709
+ self.details = self.clusters_client().edit_and_wait(**update_details)
710
+ else:
711
+ raise e
704
712
 
705
713
  logger.info(
706
714
  "Updated %s",
707
715
  self
708
716
  )
709
717
 
710
- self.install_libraries(libraries=libraries, wait_timeout=None, raise_error=False)
711
-
712
718
  return self
713
719
 
714
720
  def list_clusters(self) -> Iterator["Cluster"]:
@@ -816,7 +822,6 @@ class Cluster(WorkspaceService):
816
822
 
817
823
  return self
818
824
 
819
- @retry(tries=4)
820
825
  def restart(
821
826
  self,
822
827
  ):
@@ -195,6 +195,7 @@ class StatementResult:
195
195
  Returns:
196
196
  The result manifest or None for Spark SQL results.
197
197
  """
198
+ self.wait()
198
199
  return self.response.manifest
199
200
 
200
201
  @property
@@ -204,6 +205,7 @@ class StatementResult:
204
205
  Returns:
205
206
  The statement result payload from the API.
206
207
  """
208
+ self.wait()
207
209
  return self.response.result
208
210
 
209
211
  @property
@@ -253,7 +255,6 @@ class StatementResult:
253
255
  self, self.disposition, Disposition.EXTERNAL_LINKS
254
256
  )
255
257
 
256
- self.wait()
257
258
  result_data = self.result
258
259
  wsdk = self.workspace.sdk()
259
260
 
@@ -320,6 +321,8 @@ class StatementResult:
320
321
  f"Statement {self.statement_id} {self.state}: " + " | ".join(parts)
321
322
  )
322
323
 
324
+ return self
325
+
323
326
  def wait(
324
327
  self,
325
328
  timeout: Optional[int] = None,
@@ -339,20 +342,21 @@ class StatementResult:
339
342
 
340
343
  start = time.time()
341
344
  poll_interval = poll_interval or 1
342
- current = self
343
345
 
344
346
  while not self.done:
345
347
  # still running / queued / pending
346
348
  if timeout is not None and (time.time() - start) > timeout:
347
349
  raise TimeoutError(
348
- f"Statement {current.statement_id} did not finish within {timeout} seconds "
349
- f"(last state={current})"
350
+ f"Statement {self.statement_id} did not finish within {timeout} seconds "
351
+ f"(last state={self.state})"
350
352
  )
351
353
 
352
354
  poll_interval = max(10, poll_interval * 1.2)
353
355
  time.sleep(poll_interval)
354
356
 
355
- return current
357
+ self.raise_for_status()
358
+
359
+ return self
356
360
 
357
361
  def arrow_schema(self):
358
362
  """Return the Arrow schema for the result.
@@ -546,7 +546,15 @@ class CallableSerde:
546
546
  Returns Python code string to execute in another interpreter.
547
547
  Prints one line: "{result_tag}:{base64(blob)}"
548
548
  where blob is raw dill bytes or framed+zlib.
549
+
550
+ Also compresses the input call payload (args/kwargs) using the same framing
551
+ scheme when it exceeds byte_limit.
549
552
  """
553
+ import base64
554
+ import json
555
+ import struct
556
+ import zlib
557
+
550
558
  args = args or ()
551
559
  kwargs = kwargs or {}
552
560
 
@@ -555,13 +563,32 @@ class CallableSerde:
555
563
  dump_env=dump_env,
556
564
  filter_used_globals=filter_used_globals,
557
565
  env_keys=env_keys,
558
- env_variables=env_variables
566
+ env_variables=env_variables,
559
567
  )
560
568
  serde_json = json.dumps(serde_dict, ensure_ascii=False)
561
569
 
562
- call_payload_b64 = base64.b64encode(
563
- dill.dumps((args, kwargs), recurse=True)
564
- ).decode("ascii")
570
+ # --- input payload compression (args/kwargs) ---
571
+ MAGIC = b"CS1"
572
+ FLAG_COMPRESSED = 1
573
+
574
+ def _pick_level(n: int, limit: int) -> int:
575
+ ratio = n / max(1, limit)
576
+ x = min(1.0, max(0.0, (ratio - 1.0) / 3.0))
577
+ return max(1, min(9, int(round(1 + 8 * x))))
578
+
579
+ def _encode_blob(raw: bytes, limit: int) -> bytes:
580
+ if len(raw) <= limit:
581
+ return raw
582
+ level = _pick_level(len(raw), limit)
583
+ compressed = zlib.compress(raw, level)
584
+ if len(compressed) >= len(raw):
585
+ return raw
586
+ header = MAGIC + struct.pack(">BIB", FLAG_COMPRESSED, len(raw), level)
587
+ return header + compressed
588
+
589
+ call_raw = dill.dumps((args, kwargs), recurse=True)
590
+ call_blob = _encode_blob(call_raw, int(byte_limit))
591
+ call_payload_b64 = base64.b64encode(call_blob).decode("ascii")
565
592
 
566
593
  # NOTE: plain string template + replace. No f-string. No brace escaping.
567
594
  template = r"""
@@ -595,6 +622,19 @@ def _encode_result(raw: bytes, byte_limit: int) -> bytes:
595
622
  header = MAGIC + struct.pack(">BIB", FLAG_COMPRESSED, len(raw), level)
596
623
  return header + compressed
597
624
 
625
+ def _decode_blob(blob: bytes) -> bytes:
626
+ # If it's framed (MAGIC + header), decompress; else return as-is.
627
+ if isinstance(blob, (bytes, bytearray)) and len(blob) >= 3 and blob[:3] == MAGIC:
628
+ if len(blob) >= 3 + 6:
629
+ flag, orig_len, level = struct.unpack(">BIB", blob[3:3+6])
630
+ if flag & FLAG_COMPRESSED:
631
+ raw = zlib.decompress(blob[3+6:])
632
+ # best-effort sanity check; don't hard-fail on mismatch
633
+ if isinstance(orig_len, int) and orig_len > 0 and len(raw) != orig_len:
634
+ return raw
635
+ return raw
636
+ return blob
637
+
598
638
  def _needed_globals(fn) -> set[str]:
599
639
  names = set()
600
640
  try:
@@ -657,7 +697,9 @@ if env_b64:
657
697
  meta = serde.get("env_meta") or {}
658
698
  _apply_env(fn, env, bool(meta.get("filter_used_globals", True)))
659
699
 
660
- args, kwargs = dill.loads(base64.b64decode(__CALL_PAYLOAD_B64__))
700
+ call_blob = base64.b64decode(__CALL_PAYLOAD_B64__)
701
+ call_raw = _decode_blob(call_blob)
702
+ args, kwargs = dill.loads(call_raw)
661
703
 
662
704
  res = fn(*args, **kwargs)
663
705
  raw = dill.dumps(res, recurse=True)
yggdrasil/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.38"
1
+ __version__ = "0.1.41"
File without changes