snowpark-connect 0.30.0__py3-none-any.whl → 0.30.1__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.

Potentially problematic release.


This version of snowpark-connect might be problematic. Click here for more details.

Files changed (22) hide show
  1. snowflake/snowpark_connect/config.py +3 -0
  2. snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2_grpc.py +4 -0
  3. snowflake/snowpark_connect/proto/snowflake_relation_ext_pb2_grpc.py +4 -0
  4. snowflake/snowpark_connect/relation/io_utils.py +61 -4
  5. snowflake/snowpark_connect/relation/map_row_ops.py +13 -2
  6. snowflake/snowpark_connect/relation/map_stats.py +20 -5
  7. snowflake/snowpark_connect/relation/read/map_read.py +9 -0
  8. snowflake/snowpark_connect/relation/utils.py +19 -2
  9. snowflake/snowpark_connect/relation/write/map_write.py +15 -29
  10. snowflake/snowpark_connect/utils/session.py +0 -1
  11. snowflake/snowpark_connect/utils/telemetry.py +75 -18
  12. snowflake/snowpark_connect/version.py +1 -1
  13. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.30.1.dist-info}/METADATA +1 -1
  14. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.30.1.dist-info}/RECORD +22 -20
  15. {snowpark_connect-0.30.0.data → snowpark_connect-0.30.1.data}/scripts/snowpark-connect +0 -0
  16. {snowpark_connect-0.30.0.data → snowpark_connect-0.30.1.data}/scripts/snowpark-session +0 -0
  17. {snowpark_connect-0.30.0.data → snowpark_connect-0.30.1.data}/scripts/snowpark-submit +0 -0
  18. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.30.1.dist-info}/WHEEL +0 -0
  19. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.30.1.dist-info}/licenses/LICENSE-binary +0 -0
  20. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.30.1.dist-info}/licenses/LICENSE.txt +0 -0
  21. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.30.1.dist-info}/licenses/NOTICE-binary +0 -0
  22. {snowpark_connect-0.30.0.dist-info → snowpark_connect-0.30.1.dist-info}/top_level.txt +0 -0
@@ -143,6 +143,9 @@ class GlobalConfig:
143
143
  # Control whether repartition(n) on a DataFrame forces splitting into n files during writes
144
144
  # This matches spark behavior more closely, but introduces overhead.
145
145
  "snowflake.repartition.for.writes": "false",
146
+ "snowpark.connect.structured_types.fix": str(
147
+ snowpark.context._enable_fix_2360274
148
+ ).lower(),
146
149
  }
147
150
 
148
151
  boolean_config_list = [
@@ -0,0 +1,4 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
@@ -0,0 +1,4 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
@@ -4,6 +4,8 @@
4
4
 
5
5
  from urllib.parse import urlparse
6
6
 
7
+ from pyspark.errors.exceptions.base import AnalysisException
8
+
7
9
  CLOUD_PREFIX_TO_CLOUD = {
8
10
  "abfss": "azure",
9
11
  "wasbs": "azure",
@@ -12,10 +14,28 @@ CLOUD_PREFIX_TO_CLOUD = {
12
14
  }
13
15
 
14
16
  SUPPORTED_COMPRESSION_PER_FORMAT = {
15
- "csv": {"AUTO", "GZIP", "BZ2", "BROTLI", "ZSTD", "DEFLATE", "RAW_DEFLATE", "NONE"},
16
- "json": {"AUTO", "GZIP", "BZ2", "BROTLI", "ZSTD", "DEFLATE", "RAW_DEFLATE", "NONE"},
17
- "parquet": {"AUTO", "LZO", "SNAPPY", "NONE"},
18
- "text": {"NONE"},
17
+ "csv": {
18
+ "GZIP",
19
+ "BZ2",
20
+ "BROTLI",
21
+ "ZSTD",
22
+ "DEFLATE",
23
+ "RAW_DEFLATE",
24
+ "NONE",
25
+ "UNCOMPRESSED",
26
+ },
27
+ "json": {
28
+ "GZIP",
29
+ "BZ2",
30
+ "BROTLI",
31
+ "ZSTD",
32
+ "DEFLATE",
33
+ "RAW_DEFLATE",
34
+ "NONE",
35
+ "UNCOMPRESSED",
36
+ },
37
+ "parquet": {"LZO", "SNAPPY", "NONE", "UNCOMPRESSED"},
38
+ "text": {"NONE", "UNCOMPRESSED"},
19
39
  }
20
40
 
21
41
 
@@ -29,6 +49,43 @@ def is_supported_compression(format: str, compression: str | None) -> bool:
29
49
  return compression in supported_compressions_for_format(format)
30
50
 
31
51
 
52
+ def get_compression_for_source_and_options(
53
+ source: str, options: dict[str, str], from_read: bool = False
54
+ ) -> str | None:
55
+ """
56
+ Determines the compression type to use for a given data source and options.
57
+ Args:
58
+ source (str): The data source format (e.g., "csv", "json", "parquet", "text").
59
+ options (dict[str, str]): A dictionary of options that may include a "compression" key.
60
+ Returns:
61
+ str: The compression type to use (e.g., "GZIP", "SNAPPY", "NONE").
62
+ Raises:
63
+ AnalysisException: If the specified compression is not supported for the given source format.
64
+ """
65
+ # From read, we don't have a default compression
66
+ if from_read and "compression" not in options:
67
+ return None
68
+
69
+ # Get compression from options for proper filename generation
70
+ default_compression = "NONE" if source != "parquet" else "snappy"
71
+ compression = options.get("compression", default_compression).upper()
72
+ if compression == "UNCOMPRESSED":
73
+ compression = "NONE"
74
+
75
+ if not is_supported_compression(source, compression):
76
+ supported_compressions = supported_compressions_for_format(source)
77
+ raise AnalysisException(
78
+ f"Compression {compression} is not supported for {source} format. "
79
+ + (
80
+ f"Supported compressions: {sorted(supported_compressions)}"
81
+ if supported_compressions
82
+ else "None compression supported for this format."
83
+ )
84
+ )
85
+
86
+ return compression
87
+
88
+
32
89
  def get_cloud_from_url(
33
90
  url: str,
34
91
  ):
@@ -35,6 +35,9 @@ from snowflake.snowpark_connect.expression.map_expression import (
35
35
  )
36
36
  from snowflake.snowpark_connect.expression.typer import ExpressionTyper
37
37
  from snowflake.snowpark_connect.relation.map_relation import map_relation
38
+ from snowflake.snowpark_connect.utils.identifiers import (
39
+ split_fully_qualified_spark_name,
40
+ )
38
41
  from snowflake.snowpark_connect.utils.telemetry import (
39
42
  SnowparkConnectNotImplementedError,
40
43
  )
@@ -131,11 +134,19 @@ def map_fillna(
131
134
  input_df = input_container.dataframe
132
135
 
133
136
  if len(rel.fill_na.cols) > 0:
137
+ if rel.fill_na.cols == ["*"]:
138
+ # Expand "*" to all columns
139
+ spark_col_names = input_container.column_map.get_spark_columns()
140
+ else:
141
+ spark_col_names = list(rel.fill_na.cols)
142
+
143
+ # We don't validate the fully qualified spark name here as fillNa is no-op for structured type colums.
144
+ # It only works for scalar type columns like float, int, string or bool.
134
145
  columns: list[str] = [
135
146
  input_container.column_map.get_snowpark_column_name_from_spark_column_name(
136
- c
147
+ split_fully_qualified_spark_name(c)[0]
137
148
  )
138
- for c in rel.fill_na.cols
149
+ for c in spark_col_names
139
150
  ]
140
151
  values = [get_literal_field_and_name(v)[0] for v in rel.fill_na.values]
141
152
  if len(values) == 1:
@@ -309,9 +309,28 @@ def map_freq_items(rel: relation_proto.Relation) -> DataFrameContainer:
309
309
  cols = input_container.column_map.get_snowpark_column_names_from_spark_column_names(
310
310
  list(rel.freq_items.cols)
311
311
  )
312
+
313
+ # handle empty DataFrame case
314
+ row_count = input_df.count()
315
+
316
+ for sp_col_name in cols:
317
+ spark_col_names.append(
318
+ f"{input_container.column_map.get_spark_column_name_from_snowpark_column_name(sp_col_name)}_freqItems"
319
+ )
320
+
321
+ if row_count == 0:
322
+ # If DataFrame is empty, return empty arrays for each column
323
+ empty_values = [[] for _ in cols]
324
+ approx_top_k_df = session.createDataFrame([empty_values], spark_col_names)
325
+ return DataFrameContainer.create_with_column_mapping(
326
+ dataframe=approx_top_k_df,
327
+ spark_column_names=spark_col_names,
328
+ snowpark_column_names=spark_col_names,
329
+ )
330
+
312
331
  approx_top_k_df = input_df.select(
313
332
  *[
314
- fn.function("approx_top_k")(fn.col(col), round(input_df.count() / support))
333
+ fn.function("approx_top_k")(fn.col(col), round(row_count / support))
315
334
  for col in cols
316
335
  ]
317
336
  )
@@ -330,10 +349,6 @@ def map_freq_items(rel: relation_proto.Relation) -> DataFrameContainer:
330
349
  for value in approx_top_k_values
331
350
  ]
332
351
 
333
- for sp_col_name in cols:
334
- spark_col_names.append(
335
- f"{input_container.column_map.get_spark_column_name_from_snowpark_column_name(sp_col_name)}_freqItems"
336
- )
337
352
  approx_top_k_df = session.createDataFrame([filtered_values], spark_col_names)
338
353
 
339
354
  return DataFrameContainer.create_with_column_mapping(
@@ -17,6 +17,7 @@ from snowflake.snowpark_connect.config import global_config
17
17
  from snowflake.snowpark_connect.dataframe_container import DataFrameContainer
18
18
  from snowflake.snowpark_connect.relation.io_utils import (
19
19
  convert_file_prefix_path,
20
+ get_compression_for_source_and_options,
20
21
  is_cloud_path,
21
22
  )
22
23
  from snowflake.snowpark_connect.relation.read.map_read_table import map_read_table
@@ -237,6 +238,14 @@ def _read_file(
237
238
  )
238
239
  upload_files_if_needed(paths, clean_source_paths, session, read_format)
239
240
  paths = [_quote_stage_path(path) for path in paths]
241
+
242
+ if read_format in ("csv", "text", "json", "parquet"):
243
+ compression = get_compression_for_source_and_options(
244
+ read_format, options, from_read=True
245
+ )
246
+ if compression is not None:
247
+ options["compression"] = compression
248
+
240
249
  match read_format:
241
250
  case "csv":
242
251
  from snowflake.snowpark_connect.relation.read.map_read_csv import (
@@ -92,6 +92,21 @@ TYPE_MAP_FOR_TO_SCHEMA = {
92
92
  }
93
93
 
94
94
 
95
+ # This mapping is used to map the compression type to the extension of the file.
96
+ FILE_COMPRESSION_TO_EXTENSION = {
97
+ "GZIP": "gz",
98
+ "BZ2": "bz2",
99
+ "BROTLI": "br",
100
+ "ZSTD": "zst",
101
+ "DEFLATE": "deflate",
102
+ "RAW_DEFLATE": "raw_deflate",
103
+ "SNAPPY": "snappy",
104
+ "LZO": "lzo",
105
+ "LZ4": "lz4",
106
+ "BZIP2": "bz2",
107
+ }
108
+
109
+
95
110
  def get_df_with_partition_row_number(
96
111
  container: DataFrameContainer,
97
112
  plan_id: int | None,
@@ -186,13 +201,15 @@ def generate_spark_compatible_filename(
186
201
 
187
202
  # Add compression if specified and not 'none'
188
203
  if compression and compression.lower() not in ("none", "uncompressed"):
189
- compression_part = f".{compression.lower()}"
204
+ compression_part = f".{FILE_COMPRESSION_TO_EXTENSION.get(compression.upper(), compression.lower())}"
190
205
  else:
191
206
  compression_part = ""
192
207
 
193
208
  # Add format extension if specified
194
- if format_ext:
209
+ if format_ext == "parquet":
195
210
  return f"{base_name}{compression_part}.{format_ext}"
211
+ elif format_ext is not None and format_ext != "":
212
+ return f"{base_name}.{format_ext}{compression_part}"
196
213
  else:
197
214
  return f"{base_name}{compression_part}"
198
215
 
@@ -35,9 +35,8 @@ from snowflake.snowpark_connect.config import (
35
35
  from snowflake.snowpark_connect.dataframe_container import DataFrameContainer
36
36
  from snowflake.snowpark_connect.relation.io_utils import (
37
37
  convert_file_prefix_path,
38
+ get_compression_for_source_and_options,
38
39
  is_cloud_path,
39
- is_supported_compression,
40
- supported_compressions_for_format,
41
40
  )
42
41
  from snowflake.snowpark_connect.relation.map_relation import map_relation
43
42
  from snowflake.snowpark_connect.relation.read.metadata_utils import (
@@ -147,6 +146,11 @@ def map_write(request: proto_base.ExecutePlanRequest):
147
146
 
148
147
  session: snowpark.Session = get_or_create_snowpark_session()
149
148
 
149
+ # Check for partition hint early to determine precedence over single option
150
+ partition_hint = (
151
+ result.partition_hint if hasattr(result, "partition_hint") else None
152
+ )
153
+
150
154
  # Snowflake saveAsTable doesn't support format
151
155
  if (
152
156
  write_op.HasField("table")
@@ -176,8 +180,11 @@ def map_write(request: proto_base.ExecutePlanRequest):
176
180
  # Generate Spark-compatible filename with proper extension
177
181
  extension = write_op.source if write_op.source != "text" else "txt"
178
182
 
179
- # Get compression from options for proper filename generation
180
- compression_option = write_op.options.get("compression", "none")
183
+ compression = get_compression_for_source_and_options(
184
+ write_op.source, write_op.options, from_read=False
185
+ )
186
+ if compression is not None:
187
+ write_op.options["compression"] = compression
181
188
 
182
189
  # Generate Spark-compatible filename or prefix
183
190
  # we need a random prefix to support "append" mode
@@ -203,12 +210,12 @@ def map_write(request: proto_base.ExecutePlanRequest):
203
210
  except Exception as e:
204
211
  logger.warning(f"Could not clear directory {write_path}: {e}")
205
212
 
206
- if should_write_to_single_file:
213
+ if should_write_to_single_file and partition_hint is None:
207
214
  # Single file: generate complete filename with extension
208
215
  spark_filename = generate_spark_compatible_filename(
209
216
  task_id=0,
210
217
  attempt_number=0,
211
- compression=compression_option,
218
+ compression=compression,
212
219
  format_ext=extension,
213
220
  )
214
221
  temp_file_prefix_on_stage = f"{write_path}/{spark_filename}"
@@ -217,29 +224,11 @@ def map_write(request: proto_base.ExecutePlanRequest):
217
224
  spark_filename_prefix = generate_spark_compatible_filename(
218
225
  task_id=0,
219
226
  attempt_number=0,
220
- compression=compression_option,
227
+ compression=None,
221
228
  format_ext="", # No extension for prefix
222
229
  )
223
230
  temp_file_prefix_on_stage = f"{write_path}/{spark_filename_prefix}"
224
231
 
225
- default_compression = "NONE" if write_op.source != "parquet" else "snappy"
226
- compression = write_op.options.get(
227
- "compression", default_compression
228
- ).upper()
229
-
230
- if not is_supported_compression(write_op.source, compression):
231
- supported_compressions = supported_compressions_for_format(
232
- write_op.source
233
- )
234
- raise AnalysisException(
235
- f"Compression {compression} is not supported for {write_op.source} format. "
236
- + (
237
- f"Supported compressions: {sorted(supported_compressions)}"
238
- if supported_compressions
239
- else "No compression supported for this format."
240
- )
241
- )
242
-
243
232
  parameters = {
244
233
  "location": temp_file_prefix_on_stage,
245
234
  "file_format_type": write_op.source
@@ -254,9 +243,6 @@ def map_write(request: proto_base.ExecutePlanRequest):
254
243
  # Using the base avoids coupling to exact filenames/prefixes.
255
244
  download_stage_path = write_path
256
245
 
257
- # Check for partition hint early to determine precedence over single option
258
- partition_hint = result.partition_hint
259
-
260
246
  # Apply max_file_size for both single and multi-file scenarios
261
247
  # This helps control when Snowflake splits files into multiple parts
262
248
  if max_file_size:
@@ -314,7 +300,7 @@ def map_write(request: proto_base.ExecutePlanRequest):
314
300
  per_part_prefix = generate_spark_compatible_filename(
315
301
  task_id=part_idx,
316
302
  attempt_number=0,
317
- compression=compression_option,
303
+ compression=None,
318
304
  format_ext="", # prefix only; Snowflake appends extension/counters
319
305
  )
320
306
  part_params["location"] = f"{write_path}/{per_part_prefix}"
@@ -120,7 +120,6 @@ def configure_snowpark_session(session: snowpark.Session):
120
120
  "PYTHON_SNOWPARK_USE_SCOPED_TEMP_OBJECTS": "false", # this is required for creating udfs from sproc
121
121
  "ENABLE_STRUCTURED_TYPES_IN_SNOWPARK_CONNECT_RESPONSE": "true",
122
122
  "QUERY_TAG": f"'{query_tag}'",
123
- "FEATURE_INTERVAL_TYPES": "enabled",
124
123
  }
125
124
 
126
125
  session.sql(
@@ -11,8 +11,8 @@ from abc import ABC, abstractmethod
11
11
  from collections import defaultdict
12
12
  from collections.abc import Iterable
13
13
  from contextvars import ContextVar
14
+ from dataclasses import dataclass
14
15
  from enum import Enum, unique
15
- from typing import Dict
16
16
 
17
17
  import google.protobuf.message
18
18
  import pyspark.sql.connect.proto.base_pb2 as proto_base
@@ -57,6 +57,7 @@ class TelemetryType(Enum):
57
57
 
58
58
  class EventType(Enum):
59
59
  SERVER_STARTED = "scos_server_started"
60
+ WARNING = "scos_warning"
60
61
 
61
62
 
62
63
  # global labels
@@ -106,7 +107,16 @@ REDACTED_PLAN_SUFFIXES = [
106
107
  ]
107
108
 
108
109
 
109
- def _basic_telemetry_data() -> Dict:
110
+ @dataclass
111
+ class TelemetryMessage:
112
+ """Container for telemetry messages in the processing queue."""
113
+
114
+ message: dict
115
+ timestamp: int
116
+ is_warning: bool
117
+
118
+
119
+ def _basic_telemetry_data() -> dict:
110
120
  return {
111
121
  **STATIC_TELEMETRY_DATA,
112
122
  TelemetryField.KEY_EVENT_ID.value: str(uuid.uuid4()),
@@ -123,9 +133,11 @@ def safe(func):
123
133
  def wrap(*args, **kwargs):
124
134
  try:
125
135
  func(*args, **kwargs)
126
- except Exception:
127
- # We don't really care if telemetry fails, just want to be safe for the user
128
- logger.warning(f"Telemetry operation failed: {func}", exc_info=True)
136
+ except Exception as e:
137
+ # report failed operation to telemetry
138
+ telemetry.send_warning_msg(
139
+ f"Telemetry operation {func} failed due to exception", e
140
+ )
129
141
 
130
142
  return wrap
131
143
 
@@ -528,8 +540,8 @@ class Telemetry:
528
540
  @safe
529
541
  def send_request_summary_telemetry(self):
530
542
  if self._not_in_request():
531
- logger.warning(
532
- "Truing to send request summary telemetry without initializing it"
543
+ self.send_warning_msg(
544
+ "Trying to send request summary telemetry without initializing it"
533
545
  )
534
546
  return
535
547
 
@@ -541,14 +553,56 @@ class Telemetry:
541
553
  }
542
554
  self._send(message)
543
555
 
544
- def _send(self, msg: Dict) -> None:
556
+ def send_warning_msg(self, msg: str, e: Exception = None) -> None:
557
+ # using this within @safe decorator may result in recursive loop
558
+ try:
559
+ message = self._build_warning_message(msg, e)
560
+ if not message:
561
+ return
562
+
563
+ self._send(message, is_warning=True)
564
+ except Exception:
565
+ # if there's an exception here, there's nothing we can really do about it
566
+ pass
567
+
568
+ def _build_warning_message(self, warning_msg: str, e: Exception = None) -> dict:
569
+ try:
570
+ data = {"warning_message": warning_msg}
571
+ if e is not None:
572
+ data["exception"] = repr(e)
573
+
574
+ # add session and operation id if available
575
+ spark_session_id = self._request_summary.get().get("spark_session_id", None)
576
+ if spark_session_id is not None:
577
+ data["spark_session_id"] = spark_session_id
578
+
579
+ spark_operation_id = self._request_summary.get().get(
580
+ "spark_operation_id", None
581
+ )
582
+ if spark_operation_id is not None:
583
+ data["spark_operation_id"] = spark_operation_id
584
+
585
+ message = {
586
+ **_basic_telemetry_data(),
587
+ TelemetryField.KEY_TYPE.value: TelemetryType.TYPE_EVENT.value,
588
+ TelemetryType.EVENT_TYPE.value: EventType.WARNING.value,
589
+ TelemetryField.KEY_DATA.value: data,
590
+ }
591
+ return message
592
+ except Exception:
593
+ return {}
594
+
595
+ def _send(self, msg: dict, is_warning: bool = False) -> None:
545
596
  """Queue a telemetry message for asynchronous processing."""
546
597
  if not self._is_enabled:
547
598
  return
548
599
 
549
600
  timestamp = get_time_millis()
550
601
  try:
551
- self._message_queue.put_nowait((msg, timestamp))
602
+ telemetry_msg = TelemetryMessage(
603
+ message=msg, timestamp=timestamp, is_warning=is_warning
604
+ )
605
+ self._message_queue.put_nowait(telemetry_msg)
552
606
  except queue.Full:
553
607
  # If queue is full, drop the message to avoid blocking
554
608
  logger.warning("Telemetry queue is full, dropping message")
@@ -566,13 +620,16 @@ class Telemetry:
566
620
  while True:
567
621
  try:
568
622
  # block to allow the GIL to switch threads
569
- message, timestamp = self._message_queue.get()
570
- if timestamp is None and message is None:
571
- # shutdown
623
+ telemetry_msg = self._message_queue.get()
624
+ if telemetry_msg is None:
625
+ # shutdown signal
572
626
  break
573
- self._sink.add_telemetry_data(message, timestamp)
574
- except Exception:
575
- logger.warning("Failed to add telemetry message to sink", exc_info=True)
627
+ self._sink.add_telemetry_data(
628
+ telemetry_msg.message, telemetry_msg.timestamp
629
+ )
630
+ except Exception as e:
631
+ if not telemetry_msg.is_warning:
632
+ self.send_warning_msg("Failed to add telemetry message to sink", e)
576
633
  finally:
577
634
  self._message_queue.task_done()
578
635
 
@@ -585,7 +642,7 @@ class Telemetry:
585
642
  return
586
643
 
587
644
  try:
588
- self._message_queue.put_nowait((None, None))
645
+ self._message_queue.put_nowait(None)
589
646
  # Wait for worker thread to finish
590
647
  self._worker_thread.join(timeout=3.0)
591
648
  except Exception:
@@ -594,7 +651,7 @@ class Telemetry:
594
651
  )
595
652
 
596
653
 
597
- def _error_location(e: Exception) -> Dict | None:
654
+ def _error_location(e: Exception) -> dict | None:
598
655
  """
599
656
  Inspect the exception traceback and extract the file name, line number, and function name
600
657
  from the last frame (the one that raised the exception).
@@ -675,7 +732,7 @@ def _protobuf_to_json_with_redaction(
675
732
  """Recursively convert protobuf message to dict"""
676
733
 
677
734
  if not isinstance(msg, google.protobuf.message.Message):
678
- logger.warning("Expected a protobuf message, got: %s", type(msg))
735
+ telemetry.send_warning_msg(f"Expected a protobuf message, got: {type(msg)}")
679
736
  return {}
680
737
 
681
738
  result = {}
@@ -2,4 +2,4 @@
2
2
  #
3
3
  # Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
4
4
  #
5
- VERSION = (0,30,0)
5
+ VERSION = (0,30,1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: snowpark-connect
3
- Version: 0.30.0
3
+ Version: 0.30.1
4
4
  Summary: Snowpark Connect for Spark
5
5
  Author: Snowflake, Inc
6
6
  License: Apache License, Version 2.0
@@ -1,7 +1,7 @@
1
1
  snowflake/snowpark_connect/__init__.py,sha256=Sml4x1LTNnxZyw6nnDeJrZWUi3eUAR46Rsw6N-wHUSA,605
2
2
  snowflake/snowpark_connect/client.py,sha256=K0PK8aIppghBnY0uKlDOi4WZBUhKxJQ_vRuDpB3YsbQ,2045
3
3
  snowflake/snowpark_connect/column_name_handler.py,sha256=eiqUe7YdYFxjyHOAbD9gNCstOIuroZA2INkV4KhqGMg,27407
4
- snowflake/snowpark_connect/config.py,sha256=jm0jl92VV_CIWJP4cBLcPMJ9Ee14J3oMr-fxF53lbKg,29463
4
+ snowflake/snowpark_connect/config.py,sha256=m2ZPZPaarj2GglLnsuBCgsoJ7SLq3roIC-Jr5YyKl2k,29585
5
5
  snowflake/snowpark_connect/constants.py,sha256=FBDxNUxdqWxnf6d5-eanHlYdFFyQqCqvNyZG-uOiO6Q,598
6
6
  snowflake/snowpark_connect/control_server.py,sha256=mz3huYo84hgqUB6maZxu3LYyGq7vVL1nv7-7-MjuSYY,1956
7
7
  snowflake/snowpark_connect/dataframe_container.py,sha256=0ozyUXrWErzM7Gltnb-i2o5ZyXVVeT_HCqpuYliQXwc,8798
@@ -14,7 +14,7 @@ snowflake/snowpark_connect/start_server.py,sha256=udegO0rk2FeSnXsIcCIYQW3VRlGDjB
14
14
  snowflake/snowpark_connect/tcm.py,sha256=ftncZFbVO-uyWMhF1_HYKQykB7KobHEYoyQsYbQj1EM,203
15
15
  snowflake/snowpark_connect/type_mapping.py,sha256=hAkOz9_uPi6XnFbd_KcwHqiWoqjt5ht7hlMvD7zR7Cw,45093
16
16
  snowflake/snowpark_connect/typed_column.py,sha256=Tavii8b4zMj5IWOvN6tlOVmC80W6eQct0pC_tF2nlhU,3867
17
- snowflake/snowpark_connect/version.py,sha256=SLJsRwwuumzkgzy7vBGFQsdLIAqh_x7P2gwIM1FD1ao,118
17
+ snowflake/snowpark_connect/version.py,sha256=ihyPxJymHC107aRgWHpDuSBrYCYH4zvut1JtZOdgS5o,118
18
18
  snowflake/snowpark_connect/analyze_plan/__init__.py,sha256=xsIE96jDASko3F-MeNf4T4Gg5ufthS8CejeiJDfri0M,76
19
19
  snowflake/snowpark_connect/analyze_plan/map_tree_string.py,sha256=RFSNdDwOTXOd3gm_rKRJNyDd65zQpBxBpVOOwmKaFVA,1661
20
20
  snowflake/snowpark_connect/error/__init__.py,sha256=oQo6k4zztLmNF1c5IvJLcS99J6RWY9KBTN3RJ2pKimg,249
@@ -392,11 +392,13 @@ snowflake/snowpark_connect/proto/control_pb2.pyi,sha256=DQVcgVtvo1W1tpdi8_ogBO6D
392
392
  snowflake/snowpark_connect/proto/control_pb2_grpc.py,sha256=IPHf2f27M1HElF55HH-Kvd8WCFRo6SDj_EjEzFEe_rg,5444
393
393
  snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2.py,sha256=Buyg8ACpSbx4A9S-xA5MBAhYhF6oe7YXRs7wCcAU2Wc,3632
394
394
  snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2.pyi,sha256=4LLUkliHNthv-H4yFTargdc8FIuytWrg9Ki4JU4Zm1E,4540
395
+ snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
395
396
  snowflake/snowpark_connect/proto/snowflake_rdd_pb2.pyi,sha256=IA_TC6cYM50qTlpSL0UwhmbNkNYgEYuNcZLYTxbGfBc,1780
396
397
  snowflake/snowpark_connect/proto/snowflake_relation_ext_pb2.py,sha256=now6RWB80CV5Jko0DBLFMdXYXzvfX30uhHqHb-hKe2o,4886
397
398
  snowflake/snowpark_connect/proto/snowflake_relation_ext_pb2.pyi,sha256=4PZkACNf5ulshE8yP2Sl36CXH4UBpIKvZPhzFqeEbsM,7302
399
+ snowflake/snowpark_connect/proto/snowflake_relation_ext_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
398
400
  snowflake/snowpark_connect/relation/__init__.py,sha256=xsIE96jDASko3F-MeNf4T4Gg5ufthS8CejeiJDfri0M,76
399
- snowflake/snowpark_connect/relation/io_utils.py,sha256=jBxJZaFde9T6lSWnw23af0Jz_vn0OXD86XVLCJ2og5o,2504
401
+ snowflake/snowpark_connect/relation/io_utils.py,sha256=5FzR34-rEcZkxtLSWpArzpCwr0_Zi9jNY-KM80XBj_k,4266
400
402
  snowflake/snowpark_connect/relation/map_aggregate.py,sha256=KElVYO62V3jkU8ldTCfTX2F_atP_GZAozPY1X0W42XQ,19189
401
403
  snowflake/snowpark_connect/relation/map_catalog.py,sha256=mcx6An4fqHAxy2OhOC66Xe_0aRtYPDGkBEgMK5CfaXU,5822
402
404
  snowflake/snowpark_connect/relation/map_column_ops.py,sha256=cQ9Cde2PMAGXoQWSd984nsp86JCZL7YsAHvfu8Vi50c,49199
@@ -406,22 +408,22 @@ snowflake/snowpark_connect/relation/map_join.py,sha256=I-_jifoCOtahG49maa1Ew4zQ-
406
408
  snowflake/snowpark_connect/relation/map_local_relation.py,sha256=VBfwBT75GQUe01UOZptwcYsI7zZxaIMQyTOG6kmVuJ0,15219
407
409
  snowflake/snowpark_connect/relation/map_map_partitions.py,sha256=y6WhtacyYRmV8zLv3dQtBP2asijLze363htQbgNyoak,4130
408
410
  snowflake/snowpark_connect/relation/map_relation.py,sha256=6RncDhkGXnme6m3sCzOmyfm9x0aM-aqn9H60HY-jdzg,12733
409
- snowflake/snowpark_connect/relation/map_row_ops.py,sha256=4Zj-fUQlppK1qMc5_kVP3HrcAL_tUQjWFulVTKm-QVQ,34327
411
+ snowflake/snowpark_connect/relation/map_row_ops.py,sha256=76qMXMLisEZpcjLRHkkqufKEIK8NAiGOKcwTI1N-qkY,34877
410
412
  snowflake/snowpark_connect/relation/map_sample_by.py,sha256=8ALQbeUsB89sI3uiUFqG3w1A4TtOzOAL4umdKp6-c38,1530
411
413
  snowflake/snowpark_connect/relation/map_show_string.py,sha256=-QgOCZ_Kf7qDBN6hd0-eTxXqvVvzoJxw5hGBdk9Upgs,3669
412
414
  snowflake/snowpark_connect/relation/map_sql.py,sha256=fDGsl_ZpNo2_rkhXV1cO6i6lnUAnrK-bpiBcKiCnbGU,105507
413
- snowflake/snowpark_connect/relation/map_stats.py,sha256=AH_yV-o9U2tM925wFjU6LRfwrRA4LhisKjqEfSnnmC8,14002
415
+ snowflake/snowpark_connect/relation/map_stats.py,sha256=xc0ito9lxl3HtYUnWEVuIwV0h3vdD3inSnfmJmztO1g,14493
414
416
  snowflake/snowpark_connect/relation/map_subquery_alias.py,sha256=rHgE9XUzuWWkjNPtJz3Sxzz2aFo690paHKZh9frqPXk,1456
415
417
  snowflake/snowpark_connect/relation/map_udtf.py,sha256=cfDnbZ3TRJ6eb0EVResu6GL-OwQpaEabWLbrhgWnkRw,13316
416
418
  snowflake/snowpark_connect/relation/stage_locator.py,sha256=3PnSmuubtU04wTf4B_kyFK1ag45QXBjzfoKY5mu5Gtk,8925
417
- snowflake/snowpark_connect/relation/utils.py,sha256=AhE58g0Zz2DWY9gW4JnB_iBU-r4RMnWCj4okQdHSz_4,8398
419
+ snowflake/snowpark_connect/relation/utils.py,sha256=I5June2uch3hsXoQk21y2v_UkLVsBbaJtpV8qEcwIok,8916
418
420
  snowflake/snowpark_connect/relation/catalogs/__init__.py,sha256=0yJ5Nfg7SIxudI0P7_U5EWPyiTpkMet8tSq-IwutSZo,265
419
421
  snowflake/snowpark_connect/relation/catalogs/abstract_spark_catalog.py,sha256=wujeuKotJZRzpPp_WqVB9TkfprFU2tIXTQJk_eFOR0o,9826
420
422
  snowflake/snowpark_connect/relation/catalogs/snowflake_catalog.py,sha256=e9rXL0DOAf4VBZfa-idqehLAEZoCgIoE4IDiLVvR4dQ,28475
421
423
  snowflake/snowpark_connect/relation/catalogs/utils.py,sha256=AgiBkK9Xwm9ZyjsKZYK9eTb4YZ9C5dAimD9DLlft-tY,1753
422
424
  snowflake/snowpark_connect/relation/read/__init__.py,sha256=5J3IOTKu4Qmenouz1Oz_bUu_4c6KpxtaC63mPUGLyeY,132
423
425
  snowflake/snowpark_connect/relation/read/jdbc_read_dbapi.py,sha256=nwvBYwdDTRQc8ljt4CLLaVl5M2uei1TDICJkz7CDSG8,24608
424
- snowflake/snowpark_connect/relation/read/map_read.py,sha256=y3jCOXzQrL81lz67zYnW1_1ux0uEfYRz0hueYmrv-oc,15460
426
+ snowflake/snowpark_connect/relation/read/map_read.py,sha256=9SBe9h1ZVv9QFQIfFwim2BQODToCIUclNYETZhEjKsA,15770
425
427
  snowflake/snowpark_connect/relation/read/map_read_csv.py,sha256=3piGbSdzx5SPr10KCaqF8WrjWDlCeXQlUi3d4cfpeU8,8269
426
428
  snowflake/snowpark_connect/relation/read/map_read_jdbc.py,sha256=rfuf2Gp89v-9YFhcXFGdpzmfUgYm1ml0wYN5fdu5HA8,3950
427
429
  snowflake/snowpark_connect/relation/read/map_read_json.py,sha256=VWd_g7OeE2dBMxJFvLXt4ntdN9fu8Izerdt3-RGmDYA,13255
@@ -434,7 +436,7 @@ snowflake/snowpark_connect/relation/read/reader_config.py,sha256=PMh1R5IjqqTwiAA
434
436
  snowflake/snowpark_connect/relation/read/utils.py,sha256=rIIM6d2WXHh7MLGyHNiRc9tS8b0dmyFQr7rHepIYJOU,4111
435
437
  snowflake/snowpark_connect/relation/write/__init__.py,sha256=xsIE96jDASko3F-MeNf4T4Gg5ufthS8CejeiJDfri0M,76
436
438
  snowflake/snowpark_connect/relation/write/jdbc_write_dbapi.py,sha256=GI9FyGZuQQNV-6Q8Ob-Xr0im3iAPdH-Jkyx8bjwbOuE,11931
437
- snowflake/snowpark_connect/relation/write/map_write.py,sha256=Oamzb4KOxt8uJsBxoVj6cAv77NxipVnnAkvKiDabkDA,48265
439
+ snowflake/snowpark_connect/relation/write/map_write.py,sha256=w47pAPxGj1HMZggmxsMsKQEWw47bK3DBct24nMB48aA,47553
438
440
  snowflake/snowpark_connect/relation/write/map_write_jdbc.py,sha256=1nOWRgjtZzfRwnSRGFP9V6mqBVlGhSBr2KHGHbe4JMU,1404
439
441
  snowflake/snowpark_connect/resources/java_udfs-1.0-SNAPSHOT.jar,sha256=tVyOp6tXxu9nm6SDufwQiGzfH3pnuh_7PowsMZxOolY,9773
440
442
  snowflake/snowpark_connect/utils/__init__.py,sha256=xsIE96jDASko3F-MeNf4T4Gg5ufthS8CejeiJDfri0M,76
@@ -451,9 +453,9 @@ snowflake/snowpark_connect/utils/io_utils.py,sha256=j8-t_Vvy0qJhA7EeSYlEqqmc2-os
451
453
  snowflake/snowpark_connect/utils/pandas_udtf_utils.py,sha256=3WA_9IVRZL8fnwIHo048LTg62-bPGfCDUZzYd-zjzQQ,7564
452
454
  snowflake/snowpark_connect/utils/profiling.py,sha256=ttdHzQUYarvTqJASLNuKFIax7ejO39Tv1mHKl0QjRkg,1519
453
455
  snowflake/snowpark_connect/utils/scala_udf_utils.py,sha256=RFDDMmgQ_xBWk98kdfWaw4Hla3ZqYf3UAijU4uAUNdA,23011
454
- snowflake/snowpark_connect/utils/session.py,sha256=Sd2Oj6CWcR3w1QUt8Kif_o7sxftFOAykjKtFqsKRD_I,7476
456
+ snowflake/snowpark_connect/utils/session.py,sha256=3-76jBcSQFOIJVmXvyClMI2kIz_5PJXWTHE5pcSo_8w,7431
455
457
  snowflake/snowpark_connect/utils/snowpark_connect_logging.py,sha256=23bvbALGqixJ3Ap9QWM3OpcKNK-sog2mr9liSmvwqYU,1123
456
- snowflake/snowpark_connect/utils/telemetry.py,sha256=KcM_fZHlt6v8eoqrfonzgWSZxIQjrZCGkb0RD_PuRd8,23262
458
+ snowflake/snowpark_connect/utils/telemetry.py,sha256=Eh8v7kXbkvfZFcCk_fyMUHM7KjWg7CkeIxYKzvQ1vTo,25267
457
459
  snowflake/snowpark_connect/utils/temporary_view_cache.py,sha256=M1czwb-uv0nP9w1meB72NR7cj0iryJc_OYFPztx5XuU,2080
458
460
  snowflake/snowpark_connect/utils/udf_cache.py,sha256=AmUFc6iv0UvJF8iH6kAp4BWcZ3O465qyS1pcxf5mQZ8,13342
459
461
  snowflake/snowpark_connect/utils/udf_helper.py,sha256=g-TxTs4ARyJWYgADrosfQQG-ykBBQdm1g5opslxJq_E,12563
@@ -467,17 +469,17 @@ snowflake/snowpark_decoder/dp_session.py,sha256=HIr3TfKgYl5zqaGR5xpFU9ZVkcaTB9I8
467
469
  snowflake/snowpark_decoder/spark_decoder.py,sha256=EQiCvBiqB736Bc17o3gnYGtcYVcyfGxroO5e1kbe1Co,2885
468
470
  snowflake/snowpark_decoder/_internal/proto/generated/DataframeProcessorMsg_pb2.py,sha256=2eSDqeyfMvmIJ6_rF663DrEe1dg_anrP4OpVJNTJHaQ,2598
469
471
  snowflake/snowpark_decoder/_internal/proto/generated/DataframeProcessorMsg_pb2.pyi,sha256=aIH23k52bXdw5vO3RtM5UcOjDPaWsJFx1SRUSk3qOK8,6142
470
- snowpark_connect-0.30.0.data/scripts/snowpark-connect,sha256=yZ94KqbWACxnwV8mpg8NjILvvRNjnF8B3cs3ZFNuIM4,1546
471
- snowpark_connect-0.30.0.data/scripts/snowpark-session,sha256=NMAHSonTo-nmOZSkQNlszUC0jLJ8QWEDUsUmMe2UAOw,190
472
- snowpark_connect-0.30.0.data/scripts/snowpark-submit,sha256=Zd98H9W_d0dIqMSkQLdHyW5G3myxF0t4c3vNBt2nD6A,12056
473
- snowpark_connect-0.30.0.dist-info/licenses/LICENSE-binary,sha256=fmBlX39HwTlBUyiKEznaLZGuxQy-7ndLLG_rTXjF02Y,22916
474
- snowpark_connect-0.30.0.dist-info/licenses/LICENSE.txt,sha256=Ff9cPv4xu0z7bnMTHzo4vDncOShsy33w4oJMA2xjn6c,11365
475
- snowpark_connect-0.30.0.dist-info/licenses/NOTICE-binary,sha256=elMF8brgGNJwOz8YdorzBF6-U8ZhR8F-77FfGkZng7U,57843
472
+ snowpark_connect-0.30.1.data/scripts/snowpark-connect,sha256=yZ94KqbWACxnwV8mpg8NjILvvRNjnF8B3cs3ZFNuIM4,1546
473
+ snowpark_connect-0.30.1.data/scripts/snowpark-session,sha256=NMAHSonTo-nmOZSkQNlszUC0jLJ8QWEDUsUmMe2UAOw,190
474
+ snowpark_connect-0.30.1.data/scripts/snowpark-submit,sha256=Zd98H9W_d0dIqMSkQLdHyW5G3myxF0t4c3vNBt2nD6A,12056
475
+ snowpark_connect-0.30.1.dist-info/licenses/LICENSE-binary,sha256=fmBlX39HwTlBUyiKEznaLZGuxQy-7ndLLG_rTXjF02Y,22916
476
+ snowpark_connect-0.30.1.dist-info/licenses/LICENSE.txt,sha256=Ff9cPv4xu0z7bnMTHzo4vDncOShsy33w4oJMA2xjn6c,11365
477
+ snowpark_connect-0.30.1.dist-info/licenses/NOTICE-binary,sha256=elMF8brgGNJwOz8YdorzBF6-U8ZhR8F-77FfGkZng7U,57843
476
478
  spark/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
477
479
  spark/connect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
478
480
  spark/connect/envelope_pb2.py,sha256=7Gc6OUA3vaCuTCIKamb_Iiw7W9jPTcWNEv1im20eWHM,2726
479
481
  spark/connect/envelope_pb2.pyi,sha256=VXTJSPpcxzB_dWqVdvPY4KkPhJfh0WmkX7SNHWoLhx0,3358
480
- snowpark_connect-0.30.0.dist-info/METADATA,sha256=lJFacukQEzIhfl_yoxEgZ34moo89Y65PfoymZFq3DRs,1625
481
- snowpark_connect-0.30.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
482
- snowpark_connect-0.30.0.dist-info/top_level.txt,sha256=ExnWqVpoTHRG99fu_AxXZVOz8c-De7nNu0yFCGylM8I,16
483
- snowpark_connect-0.30.0.dist-info/RECORD,,
482
+ snowpark_connect-0.30.1.dist-info/METADATA,sha256=GLLoHHRS1oJ03td7EIC8N3EsPqmw7KH3xaZbNNr2wi4,1625
483
+ snowpark_connect-0.30.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
484
+ snowpark_connect-0.30.1.dist-info/top_level.txt,sha256=ExnWqVpoTHRG99fu_AxXZVOz8c-De7nNu0yFCGylM8I,16
485
+ snowpark_connect-0.30.1.dist-info/RECORD,,