Skip to content

Commit 053c2fc

Browse files
authored
fix: zfill for old polars and pyarrow versions (#2736)
* fix: zfill for old polars and pyarrow versions * wildcard in coverage exclude
1 parent fd44732 commit 053c2fc

File tree

4 files changed

+49
-9
lines changed

4 files changed

+49
-9
lines changed

narwhals/_arrow/series_str.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,16 @@ def zfill(self, width: int) -> ArrowSeries:
6767
binary_join: Incomplete = pc.binary_join_element_wise
6868
native = self.native
6969
hyphen, plus = lit("-"), lit("+")
70-
first_char, remaining_chars = self.slice(0, 1).native, self.slice(1, None).native
70+
71+
_slice_length: int | None = (
72+
self.len_chars().max()
73+
if self._compliant_series._backend_version < (13, 0)
74+
else None
75+
)
76+
first_char, remaining_chars = (
77+
self.slice(0, 1).native,
78+
self.slice(1, _slice_length).native,
79+
)
7180

7281
# Conditions
7382
less_than_width = pc.less(pc.utf8_length(native), lit(width))

narwhals/_polars/expr.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,17 @@ def __init__(self, expr: PolarsExpr) -> None:
337337

338338
def zfill(self, width: int) -> PolarsExpr:
339339
native_expr = self._compliant_expr.native
340+
backend_version = self._compliant_expr._backend_version
340341
native_result = native_expr.str.zfill(width)
341342

342-
if self._compliant_expr._backend_version <= (1, 30, 0):
343+
if backend_version < (0, 20, 5): # pragma: no cover
344+
# Reason:
345+
# `TypeError: argument 'length': 'Expr' object cannot be interpreted as an integer`
346+
# in `native_expr.str.slice(1, length)`
347+
msg = "`zfill` is only available in 'polars>=0.20.5', found version '0.20.4'."
348+
raise NotImplementedError(msg)
349+
350+
if backend_version <= (1, 30, 0):
343351
length = native_expr.str.len_chars()
344352
less_than_width = length < width
345353
plus = "+"

pyproject.toml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,7 @@ exclude_also = [
280280
"if .*implementation.is_pyspark_connect",
281281
'request.applymarker\(pytest.mark.xfail',
282282
'backend_version <',
283-
'if "cudf" in str\(constructor',
284-
'if "modin" in str\(constructor',
285-
'if "pyspark" in str\(constructor',
286-
'if "pyspark_connect" in str\(constructor',
283+
'if ".*" in str\(constructor',
287284
'pytest.skip\(',
288285
'assert_never\(',
289286
]

tests/expr_and_series/str/zfill_test.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
import pytest
44

55
import narwhals as nw
6-
from tests.utils import PANDAS_VERSION, Constructor, ConstructorEager, assert_equal_data
6+
from tests.utils import (
7+
PANDAS_VERSION,
8+
POLARS_VERSION,
9+
Constructor,
10+
ConstructorEager,
11+
assert_equal_data,
12+
)
713

814
data = {"a": ["-1", "+1", "1", "12", "123", "99999", "+9999", None]}
915
expected = {"a": ["-01", "+01", "001", "012", "123", "99999", "+9999", None]}
@@ -16,7 +22,6 @@ def uses_pyarrow_backend(constructor: Constructor | ConstructorEager) -> bool:
1622
}
1723

1824

19-
@pytest.mark.skipif(PANDAS_VERSION < (1, 5), reason="different zfill behavior")
2025
def test_str_zfill(request: pytest.FixtureRequest, constructor: Constructor) -> None:
2126
if uses_pyarrow_backend(constructor):
2227
reason = (
@@ -25,12 +30,22 @@ def test_str_zfill(request: pytest.FixtureRequest, constructor: Constructor) ->
2530
)
2631
request.applymarker(pytest.mark.xfail(reason=reason))
2732

33+
if "pandas" in str(constructor) and PANDAS_VERSION < (1, 5):
34+
reason = "different zfill behavior"
35+
pytest.skip(reason=reason)
36+
37+
if "polars" in str(constructor) and POLARS_VERSION < (0, 20, 5):
38+
reason = (
39+
"`TypeError: argument 'length': 'Expr' object cannot be interpreted as an integer`"
40+
"in `expr.str.slice(1, length)`"
41+
)
42+
pytest.skip(reason=reason)
43+
2844
df = nw.from_native(constructor(data))
2945
result = df.select(nw.col("a").str.zfill(3))
3046
assert_equal_data(result, expected)
3147

3248

33-
@pytest.mark.skipif(PANDAS_VERSION < (1, 5), reason="different zfill behavior")
3449
def test_str_zfill_series(
3550
request: pytest.FixtureRequest, constructor_eager: ConstructorEager
3651
) -> None:
@@ -41,6 +56,17 @@ def test_str_zfill_series(
4156
)
4257
request.applymarker(pytest.mark.xfail(reason=reason))
4358

59+
if "pandas" in str(constructor_eager) and PANDAS_VERSION < (1, 5):
60+
reason = "different zfill behavior"
61+
pytest.skip(reason=reason)
62+
63+
if "polars" in str(constructor_eager) and POLARS_VERSION < (0, 20, 5):
64+
reason = (
65+
"`TypeError: argument 'length': 'Expr' object cannot be interpreted as an integer`"
66+
"in `expr.str.slice(1, length)`"
67+
)
68+
pytest.skip(reason=reason)
69+
4470
df = nw.from_native(constructor_eager(data), eager_only=True)
4571
result = df["a"].str.zfill(3)
4672
assert_equal_data({"a": result}, expected)

0 commit comments

Comments
 (0)