Skip to content

chore(typing): SparkLikeExpr properties #2152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
47e768d
chore(typing): Add typing for `SparkLikeExpr` properties
dangotbanned Mar 5, 2025
7bb9131
chore: fix typing and simplify `SparkLikeExprStringNamespace.to_datet…
dangotbanned Mar 5, 2025
89eeed5
rename function
EdAbati Mar 6, 2025
f730d52
use single chars in set
EdAbati Mar 6, 2025
fda0fec
Merge branch 'main' into spark-expr-typing
dangotbanned Mar 6, 2025
e19dcdf
fix: Remove timezone offset replacement
dangotbanned Mar 6, 2025
a4b619c
test: Adds `test_to_datetime_tz_aware`
dangotbanned Mar 6, 2025
2367125
test: possibly fix `pyarrow` in ci?
dangotbanned Mar 6, 2025
fb48654
test: xfail polars `3.8`, fix false positive pyarrow
dangotbanned Mar 6, 2025
75e48cc
test: narrower xfail, tz-less expected?
dangotbanned Mar 6, 2025
194ef83
test: account for `pyarrow` version changes
dangotbanned Mar 6, 2025
ce3145d
test: maybe fix `pyspark`
dangotbanned Mar 6, 2025
ef015af
Merge branch 'main' into spark-expr-typing
dangotbanned Mar 6, 2025
75e4477
Merge branch 'main' into spark-expr-typing
dangotbanned Mar 7, 2025
4470a99
revert: go back to typing fixes only
dangotbanned Mar 7, 2025
77a264c
chore: ignore `format` shadowing
dangotbanned Mar 7, 2025
fbf2459
Merge remote-tracking branch 'upstream/main' into spark-expr-typing
dangotbanned Mar 7, 2025
fb2820b
Merge branch 'main' into spark-expr-typing
dangotbanned Mar 7, 2025
311c7ea
keep logic the same I hope
dangotbanned Mar 7, 2025
7936aa8
Merge branch 'spark-expr-typing' of https://github.com/narwhals-dev/n…
dangotbanned Mar 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions narwhals/_spark_like/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

if TYPE_CHECKING:
from pyspark.sql import Column
from pyspark.sql import Window
from typing_extensions import Self

from narwhals._spark_like.dataframe import SparkLikeLazyFrame
Expand Down Expand Up @@ -78,7 +79,11 @@ def func(df: SparkLikeLazyFrame) -> Sequence[Column]:
)

@property
def _F(self: Self) -> Any: # noqa: N802
def _F(self: Self): # type: ignore[no-untyped-def] # noqa: ANN202, N802
if TYPE_CHECKING:
from pyspark.sql import functions

return functions
if self._implementation is Implementation.SQLFRAME:
from sqlframe.base.session import _BaseSession

Expand All @@ -91,7 +96,11 @@ def _F(self: Self) -> Any: # noqa: N802
return functions

@property
def _native_dtypes(self: Self) -> Any:
def _native_dtypes(self: Self): # type: ignore[no-untyped-def] # noqa: ANN202
if TYPE_CHECKING:
from pyspark.sql import types

return types
if self._implementation is Implementation.SQLFRAME:
from sqlframe.base.session import _BaseSession

Expand All @@ -104,7 +113,7 @@ def _native_dtypes(self: Self) -> Any:
return types

@property
def _Window(self: Self) -> Any: # noqa: N802
def _Window(self: Self) -> type[Window]: # noqa: N802
if self._implementation is Implementation.SQLFRAME:
from sqlframe.base.session import _BaseSession

Expand Down
48 changes: 15 additions & 33 deletions narwhals/_spark_like/expr_str.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from functools import partial
from typing import TYPE_CHECKING
from typing import overload

if TYPE_CHECKING:
from pyspark.sql import Column
Expand Down Expand Up @@ -107,47 +107,29 @@ def to_lowercase(self: Self) -> SparkLikeExpr:
)

def to_datetime(self: Self, format: str | None) -> SparkLikeExpr: # noqa: A002
is_naive = (
format is not None
and "%s" not in format
and "%z" not in format
and "Z" not in format
)
function = (
self._compliant_expr._F.to_timestamp_ntz
if is_naive
else self._compliant_expr._F.to_timestamp
)
pyspark_format = strptime_to_pyspark_format(format)
format = (
self._compliant_expr._F.lit(pyspark_format) if is_naive else pyspark_format
)
F = self._compliant_expr._F # noqa: N806
if not format:
function = F.to_timestamp
elif is_naive_format(format):
function = partial(
F.to_timestamp_ntz, format=F.lit(strptime_to_pyspark_format(format))
)
else:
format = strptime_to_pyspark_format(format)
function = partial(F.to_timestamp, format=format)
return self._compliant_expr._from_call(
lambda _input: function(
self._compliant_expr._F.replace(
_input,
self._compliant_expr._F.lit("T"),
self._compliant_expr._F.lit(" "),
),
format=format,
),
lambda _input: function(F.replace(_input, F.lit("T"), F.lit(" "))),
"to_datetime",
)


@overload
def strptime_to_pyspark_format(format: None) -> None: ...


@overload
def strptime_to_pyspark_format(format: str) -> str: ...
def is_naive_format(format: str) -> bool: # noqa: A002
return not any(x in format for x in ("%s", "%z", "Z"))


def strptime_to_pyspark_format(format: str | None) -> str | None: # noqa: A002
def strptime_to_pyspark_format(format: str) -> str: # noqa: A002
"""Converts a Python strptime datetime format string to a PySpark datetime format string."""
# Mapping from Python strptime format to PySpark format
if format is None:
return None

# see https://spark.apache.org/docs/latest/sql-ref-datetime-pattern.html
# and https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
Expand Down
Loading