sqlframe 3.38.1__py3-none-any.whl → 3.39.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.
sqlframe/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '3.38.1'
21
- __version_tuple__ = version_tuple = (3, 38, 1)
20
+ __version__ = version = '3.39.0'
21
+ __version_tuple__ = version_tuple = (3, 39, 0)
@@ -2318,6 +2318,14 @@ def array_distinct(col: ColumnOrName) -> Column:
2318
2318
  if session._is_bigquery:
2319
2319
  return array_distinct_bgutil(col)
2320
2320
 
2321
+ if session._is_duckdb:
2322
+ # DuckDB's array_distinct removes nulls, but we need to preserve them
2323
+ # Check if original array contains null and append it back if needed
2324
+ original_col = Column.ensure_col(col)
2325
+ distinct_result = Column.invoke_anonymous_function(col, "ARRAY_DISTINCT")
2326
+ has_null = array_position(original_col, lit(None)) > lit(0)
2327
+ return when(has_null, array_append(distinct_result, lit(None))).otherwise(distinct_result)
2328
+
2321
2329
  return Column.invoke_anonymous_function(col, "ARRAY_DISTINCT")
2322
2330
 
2323
2331
 
@@ -2564,7 +2572,7 @@ def shuffle(col: ColumnOrName) -> Column:
2564
2572
 
2565
2573
  @meta(unsupported_engines="snowflake")
2566
2574
  def reverse(col: ColumnOrName) -> Column:
2567
- return Column.invoke_anonymous_function(col, "REVERSE")
2575
+ return Column.invoke_expression_over_column(col, expression.Reverse)
2568
2576
 
2569
2577
 
2570
2578
  @meta(unsupported_engines=["bigquery", "postgres"])
@@ -3211,9 +3219,9 @@ def current_user() -> Column:
3211
3219
  return Column.invoke_expression_over_column(None, expression.CurrentUser)
3212
3220
 
3213
3221
 
3214
- @meta(unsupported_engines="*")
3222
+ @meta()
3215
3223
  def date_from_unix_date(days: ColumnOrName) -> Column:
3216
- return Column.invoke_anonymous_function(days, "date_from_unix_date")
3224
+ return Column.invoke_expression_over_column(days, expression.DateFromUnixDate)
3217
3225
 
3218
3226
 
3219
3227
  @meta(unsupported_engines="*")
@@ -6623,7 +6631,7 @@ def unix_micros(col: ColumnOrName) -> Column:
6623
6631
 
6624
6632
  col = to_timestamp(col)
6625
6633
 
6626
- return Column.invoke_anonymous_function(col, "unix_micros")
6634
+ return Column.invoke_expression_over_column(col, expression.UnixMicros)
6627
6635
 
6628
6636
 
6629
6637
  @meta()
@@ -6643,15 +6651,10 @@ def unix_millis(col: ColumnOrName) -> Column:
6643
6651
  """
6644
6652
  from sqlframe.base.function_alternatives import unix_millis_multiply_epoch
6645
6653
 
6646
- if (
6647
- _get_session()._is_bigquery
6648
- or _get_session()._is_duckdb
6649
- or _get_session()._is_postgres
6650
- or _get_session()._is_snowflake
6651
- ):
6654
+ if _get_session()._is_duckdb or _get_session()._is_postgres or _get_session()._is_snowflake:
6652
6655
  return unix_millis_multiply_epoch(col)
6653
6656
 
6654
- return Column.invoke_anonymous_function(col, "unix_millis")
6657
+ return Column.invoke_expression_over_column(col, expression.UnixMillis)
6655
6658
 
6656
6659
 
6657
6660
  @meta()
sqlframe/base/session.py CHANGED
@@ -12,7 +12,6 @@ from collections import defaultdict
12
12
  from functools import cached_property
13
13
 
14
14
  import sqlglot
15
- from dateutil.relativedelta import relativedelta
16
15
  from sqlglot import Dialect, exp
17
16
  from sqlglot.dialects.dialect import DialectType, NormalizationStrategy
18
17
  from sqlglot.expressions import parse_identifier
@@ -34,6 +33,7 @@ from sqlframe.base.table import _BaseTable
34
33
  from sqlframe.base.udf import _BaseUDFRegistration
35
34
  from sqlframe.base.util import (
36
35
  get_column_mapping_from_schema_input,
36
+ is_relativedelta_like,
37
37
  normalize_string,
38
38
  verify_pandas_installed,
39
39
  )
@@ -614,7 +614,7 @@ class _BaseSession(t.Generic[CATALOG, READER, WRITER, DF, TABLE, CONN, UDF_REGIS
614
614
  return [cls._to_value(x) for x in value]
615
615
  elif isinstance(value, datetime.datetime):
616
616
  return value.replace(tzinfo=None)
617
- elif isinstance(value, relativedelta):
617
+ elif is_relativedelta_like(value):
618
618
  return datetime.timedelta(
619
619
  days=value.days, hours=value.hours, minutes=value.minutes, seconds=value.seconds
620
620
  )
sqlframe/base/util.py CHANGED
@@ -524,3 +524,12 @@ def split_filepath(filepath: str) -> tuple[str, str]:
524
524
  if len(split_) == 2: # noqa: PLR2004
525
525
  return split_[0] + "://", split_[1]
526
526
  return "", split_[0]
527
+
528
+
529
+ def is_relativedelta_like(value: t.Any) -> bool:
530
+ return (
531
+ hasattr(value, "years")
532
+ and hasattr(value, "months")
533
+ and hasattr(value, "weeks")
534
+ and hasattr(value, "leapdays")
535
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sqlframe
3
- Version: 3.38.1
3
+ Version: 3.39.0
4
4
  Summary: Turning PySpark Into a Universal DataFrame API
5
5
  Home-page: https://github.com/eakmanrq/sqlframe
6
6
  Author: Ryan Eakman
@@ -17,7 +17,7 @@ Requires-Python: >=3.9
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
19
  Requires-Dist: prettytable <4
20
- Requires-Dist: sqlglot <27.7,>=24.0.0
20
+ Requires-Dist: sqlglot <27.8,>=24.0.0
21
21
  Requires-Dist: typing-extensions
22
22
  Provides-Extra: bigquery
23
23
  Requires-Dist: google-cloud-bigquery-storage <3,>=2 ; extra == 'bigquery'
@@ -60,7 +60,7 @@ Requires-Dist: psycopg2 <3,>=2.8 ; extra == 'postgres'
60
60
  Provides-Extra: redshift
61
61
  Requires-Dist: redshift-connector <2.2.0,>=2.1.1 ; extra == 'redshift'
62
62
  Provides-Extra: snowflake
63
- Requires-Dist: snowflake-connector-python[secure-local-storage] <3.17,>=3.10.0 ; extra == 'snowflake'
63
+ Requires-Dist: snowflake-connector-python[secure-local-storage] <3.18,>=3.10.0 ; extra == 'snowflake'
64
64
  Provides-Extra: spark
65
65
  Requires-Dist: pyspark <3.6,>=2 ; extra == 'spark'
66
66
 
@@ -1,5 +1,5 @@
1
1
  sqlframe/__init__.py,sha256=SB80yLTITBXHI2GCDS6n6bN5ObHqgPjfpRPAUwxaots,3403
2
- sqlframe/_version.py,sha256=W9hZ3tNnMUJ8fekpKqp7Li5vIlCbNYeYxErUGlSt3GI,513
2
+ sqlframe/_version.py,sha256=D0S49ktdLOBGSUA4wMLJwNC0E4onYQxoqOk2Tlf1HW0,513
3
3
  sqlframe/py.typed,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
4
4
  sqlframe/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  sqlframe/base/_typing.py,sha256=b2clI5HI1zEZKB_3Msx3FeAJQyft44ubUifJwQRVXyQ,1298
@@ -9,17 +9,17 @@ sqlframe/base/dataframe.py,sha256=0diYONDlet8iZt49LC3vcmfXHAAZ2MovPL2pTXYHj2U,85
9
9
  sqlframe/base/decorators.py,sha256=IhE5xNQDkwJHacCvulq5WpUKyKmXm7dL2A3o5WuKGP4,2131
10
10
  sqlframe/base/exceptions.py,sha256=9Uwvqn2eAkDpqm4BrRgbL61qM-GMCbJEMAW8otxO46s,370
11
11
  sqlframe/base/function_alternatives.py,sha256=aTu3nQhIAkZoxrI1IpjpaHEAMxBNms0AnhS0EMR-TwY,51727
12
- sqlframe/base/functions.py,sha256=OVEUYh2ZCdgxeNgfCwVcvrt0fJvxCzz1YrdhR-71Ujo,227199
12
+ sqlframe/base/functions.py,sha256=Hd77xVVOBeD4wr08OeCwFJa89LHAZHsMjZXl3cg_RQs,227630
13
13
  sqlframe/base/group.py,sha256=fBm8EUve7W7xz11nybTXr09ih-yZxL_vvEiZVE1eb_0,12025
14
14
  sqlframe/base/normalize.py,sha256=nXAJ5CwxVf4DV0GsH-q1w0p8gmjSMlv96k_ez1eVul8,3880
15
15
  sqlframe/base/operations.py,sha256=g-YNcbvNKTOBbYm23GKfB3fmydlR7ZZDAuZUtXIHtzw,4438
16
16
  sqlframe/base/readerwriter.py,sha256=Nb2VJ_HBmLQp5mK8JhnFooZh2ydAaboCAFVPb-4MNX4,31241
17
- sqlframe/base/session.py,sha256=ExaGjY_lxkMi2WDwJ8wTd2uf7a2PjOOk9bx1ViEaAqA,27507
17
+ sqlframe/base/session.py,sha256=8oaEgGbyctKKEaI0GW6k7Praku7nwx3YRYgAW3mZNk0,27481
18
18
  sqlframe/base/table.py,sha256=rCeh1W5SWbtEVfkLAUiexzrZwNgmZeptLEmLcM1ABkE,6961
19
19
  sqlframe/base/transforms.py,sha256=y0j3SGDz3XCmNGrvassk1S-owllUWfkHyMgZlY6SFO4,467
20
20
  sqlframe/base/types.py,sha256=OktuJ5f7tEogOW0oupI0RBlHfzZMmKh7zGLke9cwllo,12305
21
21
  sqlframe/base/udf.py,sha256=O6hMhBUy9NVv-mhJRtfFhXTIa_-Z8Y_FkmmuOHu0l90,1117
22
- sqlframe/base/util.py,sha256=gv_kRc3LxCuQy3t4dHFldV7elB8RU5PMqIN5-xSkWSo,19107
22
+ sqlframe/base/util.py,sha256=bIzEQXiUNBLYSCGR4v8AtABu-a6LAK5kUH_lm01fVBs,19321
23
23
  sqlframe/base/window.py,sha256=7NaKDTlhun-95LEghukBCjFBwq0RHrPaajWQNCsLxok,4818
24
24
  sqlframe/base/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  sqlframe/base/mixins/catalog_mixins.py,sha256=9fZGWToz9xMJSzUl1vsVtj6TH3TysP3fBCKJLnGUQzE,23353
@@ -130,8 +130,8 @@ sqlframe/standalone/udf.py,sha256=azmgtUjHNIPs0WMVNId05SHwiYn41MKVBhKXsQJ5dmY,27
130
130
  sqlframe/standalone/window.py,sha256=6GKPzuxeSapJakBaKBeT9VpED1ACdjggDv9JRILDyV0,35
131
131
  sqlframe/testing/__init__.py,sha256=VVCosQhitU74A3NnE52O4mNtGZONapuEXcc20QmSlnQ,132
132
132
  sqlframe/testing/utils.py,sha256=PFsGZpwNUE_4-g_f43_vstTqsK0AQ2lBneb5Eb6NkFo,13008
133
- sqlframe-3.38.1.dist-info/LICENSE,sha256=VZu79YgW780qxaFJMr0t5ZgbOYEh04xWoxaWOaqIGWk,1068
134
- sqlframe-3.38.1.dist-info/METADATA,sha256=s_1Cya3IVuV_0sIR5sDWIDIWiq-3GQ1x5qn1noMqmB8,9039
135
- sqlframe-3.38.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
136
- sqlframe-3.38.1.dist-info/top_level.txt,sha256=T0_RpoygaZSF6heeWwIDQgaP0varUdSK1pzjeJZRjM8,9
137
- sqlframe-3.38.1.dist-info/RECORD,,
133
+ sqlframe-3.39.0.dist-info/LICENSE,sha256=VZu79YgW780qxaFJMr0t5ZgbOYEh04xWoxaWOaqIGWk,1068
134
+ sqlframe-3.39.0.dist-info/METADATA,sha256=JG-T37BOFNvgTz-fYiZa82Mwaj-lvFjF5EiL8_ClU7w,9039
135
+ sqlframe-3.39.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
136
+ sqlframe-3.39.0.dist-info/top_level.txt,sha256=T0_RpoygaZSF6heeWwIDQgaP0varUdSK1pzjeJZRjM8,9
137
+ sqlframe-3.39.0.dist-info/RECORD,,