snowpark-connect 0.28.1__py3-none-any.whl → 0.30.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.

Potentially problematic release.


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

Files changed (47) hide show
  1. snowflake/snowpark_connect/analyze_plan/map_tree_string.py +8 -4
  2. snowflake/snowpark_connect/client.py +65 -0
  3. snowflake/snowpark_connect/column_name_handler.py +6 -0
  4. snowflake/snowpark_connect/config.py +33 -5
  5. snowflake/snowpark_connect/execute_plan/map_execution_root.py +21 -19
  6. snowflake/snowpark_connect/expression/map_extension.py +277 -1
  7. snowflake/snowpark_connect/expression/map_sql_expression.py +107 -2
  8. snowflake/snowpark_connect/expression/map_unresolved_function.py +425 -269
  9. snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2.py +12 -10
  10. snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2.pyi +14 -2
  11. snowflake/snowpark_connect/relation/io_utils.py +21 -1
  12. snowflake/snowpark_connect/relation/map_column_ops.py +9 -4
  13. snowflake/snowpark_connect/relation/map_extension.py +21 -4
  14. snowflake/snowpark_connect/relation/map_join.py +8 -0
  15. snowflake/snowpark_connect/relation/map_map_partitions.py +7 -8
  16. snowflake/snowpark_connect/relation/map_relation.py +1 -3
  17. snowflake/snowpark_connect/relation/map_row_ops.py +116 -15
  18. snowflake/snowpark_connect/relation/map_show_string.py +14 -6
  19. snowflake/snowpark_connect/relation/map_sql.py +39 -5
  20. snowflake/snowpark_connect/relation/map_stats.py +1 -1
  21. snowflake/snowpark_connect/relation/read/map_read.py +22 -3
  22. snowflake/snowpark_connect/relation/read/map_read_csv.py +119 -29
  23. snowflake/snowpark_connect/relation/read/map_read_json.py +57 -36
  24. snowflake/snowpark_connect/relation/read/map_read_parquet.py +7 -1
  25. snowflake/snowpark_connect/relation/read/map_read_text.py +6 -1
  26. snowflake/snowpark_connect/relation/read/metadata_utils.py +159 -0
  27. snowflake/snowpark_connect/relation/stage_locator.py +85 -53
  28. snowflake/snowpark_connect/relation/write/map_write.py +67 -4
  29. snowflake/snowpark_connect/server.py +29 -16
  30. snowflake/snowpark_connect/type_mapping.py +75 -3
  31. snowflake/snowpark_connect/utils/context.py +0 -14
  32. snowflake/snowpark_connect/utils/describe_query_cache.py +6 -3
  33. snowflake/snowpark_connect/utils/io_utils.py +36 -0
  34. snowflake/snowpark_connect/utils/session.py +4 -0
  35. snowflake/snowpark_connect/utils/telemetry.py +30 -5
  36. snowflake/snowpark_connect/utils/udf_cache.py +37 -7
  37. snowflake/snowpark_connect/version.py +1 -1
  38. {snowpark_connect-0.28.1.dist-info → snowpark_connect-0.30.0.dist-info}/METADATA +3 -2
  39. {snowpark_connect-0.28.1.dist-info → snowpark_connect-0.30.0.dist-info}/RECORD +47 -45
  40. {snowpark_connect-0.28.1.data → snowpark_connect-0.30.0.data}/scripts/snowpark-connect +0 -0
  41. {snowpark_connect-0.28.1.data → snowpark_connect-0.30.0.data}/scripts/snowpark-session +0 -0
  42. {snowpark_connect-0.28.1.data → snowpark_connect-0.30.0.data}/scripts/snowpark-submit +0 -0
  43. {snowpark_connect-0.28.1.dist-info → snowpark_connect-0.30.0.dist-info}/WHEEL +0 -0
  44. {snowpark_connect-0.28.1.dist-info → snowpark_connect-0.30.0.dist-info}/licenses/LICENSE-binary +0 -0
  45. {snowpark_connect-0.28.1.dist-info → snowpark_connect-0.30.0.dist-info}/licenses/LICENSE.txt +0 -0
  46. {snowpark_connect-0.28.1.dist-info → snowpark_connect-0.30.0.dist-info}/licenses/NOTICE-binary +0 -0
  47. {snowpark_connect-0.28.1.dist-info → snowpark_connect-0.30.0.dist-info}/top_level.txt +0 -0
@@ -15,6 +15,7 @@ from pyspark.sql.connect import functions as pyspark_functions
15
15
 
16
16
  import snowflake.snowpark_connect.proto.snowflake_expression_ext_pb2 as snowflake_proto
17
17
  from snowflake.snowpark._internal.analyzer.analyzer_utils import unquote_if_quoted
18
+ from snowflake.snowpark.types import DayTimeIntervalType, YearMonthIntervalType
18
19
  from snowflake.snowpark_connect.column_name_handler import ColumnNameMap
19
20
  from snowflake.snowpark_connect.config import global_config
20
21
  from snowflake.snowpark_connect.typed_column import TypedColumn
@@ -33,6 +34,24 @@ from .typer import ExpressionTyper
33
34
 
34
35
  DECIMAL_RE = re.compile(r"decimal\((\d+), *(\d+)\)")
35
36
 
37
+ _INTERVAL_YEARMONTH_PATTERN_RE = re.compile(r"interval (year|month)( to (year|month))?")
38
+ _INTERVAL_DAYTIME_PATTERN_RE = re.compile(
39
+ r"interval (day|hour|minute|second)( to (day|hour|minute|second))?"
40
+ )
41
+
42
+ # Interval field mappings using proper constants
43
+ _YEAR_MONTH_FIELD_MAP = {
44
+ "year": YearMonthIntervalType.YEAR,
45
+ "month": YearMonthIntervalType.MONTH,
46
+ }
47
+
48
+ _DAY_TIME_FIELD_MAP = {
49
+ "day": DayTimeIntervalType.DAY,
50
+ "hour": DayTimeIntervalType.HOUR,
51
+ "minute": DayTimeIntervalType.MINUTE,
52
+ "second": DayTimeIntervalType.SECOND,
53
+ }
54
+
36
55
  _window_specs = ContextVar[dict[str, any]]("_window_specs", default={})
37
56
 
38
57
 
@@ -388,8 +407,94 @@ def map_logical_plan_expression(exp: jpype.JObject) -> expressions_proto.Express
388
407
  type_value = types_proto.DataType()
389
408
  elif type_name == "binary":
390
409
  type_value = bytes(type_value)
391
- elif type_name.startswith("interval "):
392
- type_name = "day_time_interval" # TODO
410
+ elif year_month_match := _INTERVAL_YEARMONTH_PATTERN_RE.match(type_name):
411
+ # Extract start and end fields for year-month intervals
412
+ start_field_name = year_month_match.group(1) # 'year' or 'month'
413
+ end_field_name = (
414
+ year_month_match.group(3)
415
+ if year_month_match.group(3)
416
+ else start_field_name
417
+ )
418
+
419
+ # Validate field names exist in mapping
420
+ start_field = _YEAR_MONTH_FIELD_MAP.get(start_field_name)
421
+ end_field = _YEAR_MONTH_FIELD_MAP.get(end_field_name)
422
+
423
+ if start_field is None:
424
+ raise AnalysisException(
425
+ f"Invalid year-month interval start field: '{start_field_name}'. Expected 'year' or 'month'."
426
+ )
427
+ if end_field is None:
428
+ raise AnalysisException(
429
+ f"Invalid year-month interval end field: '{end_field_name}'. Expected 'year' or 'month'."
430
+ )
431
+
432
+ # Validate field ordering (start_field should be <= end_field)
433
+ if start_field > end_field:
434
+ raise AnalysisException(
435
+ f"Invalid year-month interval: start field '{start_field_name}' must come before or equal to end field '{end_field_name}'."
436
+ )
437
+
438
+ # Use extension for year-month intervals to preserve start/end field info
439
+ literal = expressions_proto.Expression.Literal(
440
+ year_month_interval=type_value
441
+ )
442
+ any_proto = Any()
443
+ any_proto.Pack(
444
+ snowflake_proto.ExpExtension(
445
+ interval_literal=snowflake_proto.IntervalLiteralExpression(
446
+ literal=literal,
447
+ start_field=start_field,
448
+ end_field=end_field,
449
+ )
450
+ )
451
+ )
452
+ return expressions_proto.Expression(extension=any_proto)
453
+ elif day_time_match := _INTERVAL_DAYTIME_PATTERN_RE.match(type_name):
454
+ # Extract start and end fields for day-time intervals
455
+ start_field_name = day_time_match.group(
456
+ 1
457
+ ) # 'day', 'hour', 'minute', 'second'
458
+ end_field_name = (
459
+ day_time_match.group(3)
460
+ if day_time_match.group(3)
461
+ else start_field_name
462
+ )
463
+
464
+ # Validate field names exist in mapping
465
+ start_field = _DAY_TIME_FIELD_MAP.get(start_field_name)
466
+ end_field = _DAY_TIME_FIELD_MAP.get(end_field_name)
467
+
468
+ if start_field is None:
469
+ raise AnalysisException(
470
+ f"Invalid day-time interval start field: '{start_field_name}'. Expected 'day', 'hour', 'minute', or 'second'."
471
+ )
472
+ if end_field is None:
473
+ raise AnalysisException(
474
+ f"Invalid day-time interval end field: '{end_field_name}'. Expected 'day', 'hour', 'minute', or 'second'."
475
+ )
476
+
477
+ # Validate field ordering (start_field should be <= end_field)
478
+ if start_field > end_field:
479
+ raise AnalysisException(
480
+ f"Invalid day-time interval: start field '{start_field_name}' must come before or equal to end field '{end_field_name}'."
481
+ )
482
+
483
+ # Use extension for day-time intervals to preserve start/end field info
484
+ literal = expressions_proto.Expression.Literal(
485
+ day_time_interval=type_value
486
+ )
487
+ any_proto = Any()
488
+ any_proto.Pack(
489
+ snowflake_proto.ExpExtension(
490
+ interval_literal=snowflake_proto.IntervalLiteralExpression(
491
+ literal=literal,
492
+ start_field=start_field,
493
+ end_field=end_field,
494
+ )
495
+ )
496
+ )
497
+ return expressions_proto.Expression(extension=any_proto)
393
498
  elif m := DECIMAL_RE.fullmatch(type_name):
394
499
  type_name = "decimal"
395
500
  type_value = expressions_proto.Expression.Literal.Decimal(