Skip to content

Commit

Permalink
Merge branch 'main' into add-where-expression
Browse files Browse the repository at this point in the history
  • Loading branch information
aivanoved committed Aug 20, 2024
2 parents fde2e9a + cbf4bac commit 3b37c5a
Show file tree
Hide file tree
Showing 32 changed files with 262 additions and 113 deletions.
18 changes: 9 additions & 9 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,31 @@ autolabeler:
- label: breaking
title:
# Example: feat!: ...
- '/^(build|chore|ci|depr|docs|feat|fix|perf|refactor|release|test)(\(.*\))?\!\: /'
- '/^([B|b]uild|[C|c]hore|[CI|ci]|[D|d]epr|[D|d]oc|DOC|[F|f]eat|[F|f]ix|[P|p]erf|[R|r]efactor|[R|r]elease|[T|t]est)\! /'
- label: build
title:
- '/^build/'
- '/^[B|b]uild/'
- label: internal
title:
- '/^(chore|ci|refactor|test|template|bench)/'
- '/^[C|c]hore|[CI|ci]|[R|r]efactor|[T|t]est|[T|t]emplate|[B|b]ench/'
- label: deprecation
title:
- '/^depr/'
- '/^[D|d]epr/'
- label: documentation
title:
- '/(.*doc|.*docstring)/'
- '/^[D|d]oc|DOC/'
- label: enhancement
title:
- '/^(.*feat|.*enh)/'
- '/^.*feat|.*enh|Feat|ENH|Enh/'
- label: fix
title:
- '/^fix/'
- '/^[F|f]ix/'
- label: performance
title:
- '/^perf/'
- '/^[P|p]erf/'
- label: release
title:
- '/^release/'
- '/^[R|r]elease/'

version-resolver:
major:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/extremes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ jobs:
run: uv pip install --upgrade tox virtualenv setuptools pip -r requirements-dev.txt --system
- name: uninstall pyarrow
run: uv pip uninstall pyarrow --system
- name: install pyarrow nightly
run: uv pip install --pre --extra-index-url https://pypi.fury.io/arrow-nightlies/ pyarrow --system
# - name: install pyarrow nightly
# run: uv pip install --extra-index-url https://pypi.fury.io/arrow-nightlies/ --pre pyarrow --system
- name: uninstall pandas
run: uv pip uninstall pandas --system
- name: install-pandas-nightly
Expand Down
2 changes: 1 addition & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ Then, if you start the Python REPL and see the following:
```python
>>> import narwhals
>>> narwhals.__version__
'1.4.2'
'1.5.0'
```
then installation worked correctly!
2 changes: 1 addition & 1 deletion narwhals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
from narwhals.utils import maybe_convert_dtypes
from narwhals.utils import maybe_set_index

__version__ = "1.4.2"
__version__ = "1.5.0"

__all__ = [
"selectors",
Expand Down
81 changes: 80 additions & 1 deletion narwhals/_dask/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,9 @@ def fill_null(self, value: Any) -> DaskExpr:
)

def clip(
self: Self, lower_bound: Any | None = None, upper_bound: Any | None = None
self: Self,
lower_bound: Any | None = None,
upper_bound: Any | None = None,
) -> Self:
return self._from_call(
lambda _input, _lower, _upper: _input.clip(lower=_lower, upper=_upper),
Expand Down Expand Up @@ -545,6 +547,40 @@ def func(_input: Any) -> Any:
returns_scalar=False,
)

def is_duplicated(self: Self) -> Self:
def func(_input: Any) -> Any:
_name = _input.name
return (
_input.to_frame().groupby(_name).transform("size", meta=(_name, int)) > 1
)

return self._from_call(
func,
"is_duplicated",
returns_scalar=False,
)

def is_unique(self: Self) -> Self:
def func(_input: Any) -> Any:
_name = _input.name
return (
_input.to_frame().groupby(_name).transform("size", meta=(_name, int)) == 1
)

return self._from_call(
func,
"is_unique",
returns_scalar=False,
)

def is_in(self: Self, other: Any) -> Self:
return self._from_call(
lambda _input, other: _input.isin(other),
"is_in",
other,
returns_scalar=False,
)

def null_count(self: Self) -> Self:
return self._from_call(
lambda _input: _input.isna().sum(),
Expand Down Expand Up @@ -764,6 +800,49 @@ def ordinal_day(self) -> DaskExpr:
returns_scalar=False,
)

def to_string(self, format: str) -> DaskExpr: # noqa: A002
return self._expr._from_call(
lambda _input, _format: _input.dt.strftime(_format),
"strftime",
format.replace("%.f", ".%f"),
returns_scalar=False,
)

def total_minutes(self) -> DaskExpr:
return self._expr._from_call(
lambda _input: _input.dt.total_seconds() // 60,
"total_minutes",
returns_scalar=False,
)

def total_seconds(self) -> DaskExpr:
return self._expr._from_call(
lambda _input: _input.dt.total_seconds() // 1,
"total_seconds",
returns_scalar=False,
)

def total_milliseconds(self) -> DaskExpr:
return self._expr._from_call(
lambda _input: _input.dt.total_seconds() * 1000 // 1,
"total_milliseconds",
returns_scalar=False,
)

def total_microseconds(self) -> DaskExpr:
return self._expr._from_call(
lambda _input: _input.dt.total_seconds() * 1_000_000 // 1,
"total_microseconds",
returns_scalar=False,
)

def total_nanoseconds(self) -> DaskExpr:
return self._expr._from_call(
lambda _input: _input.dt.total_seconds() * 1_000_000_000 // 1,
"total_nanoseconds",
returns_scalar=False,
)


class DaskExprNameNamespace:
def __init__(self: Self, expr: DaskExpr) -> None:
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "narwhals"
version = "1.4.2"
version = "1.5.0"
authors = [
{ name="Marco Gorelli", email="[email protected]" },
]
Expand All @@ -26,6 +26,8 @@ exclude = [
]

[project.optional-dependencies]
cudf = ["cudf>=23.08.00"]
modin = ["modin"]
pandas = ["pandas>=0.25.3"]
polars = ["polars>=0.20.3"]
pyarrow = ['pyarrow>=11.0.0']
Expand Down Expand Up @@ -94,6 +96,7 @@ filterwarnings = [
'ignore:.*Do not use the `random` module inside strategies',
'ignore:.*You are using pyarrow version',
'ignore:.*but when imported by',
'ignore:Distributing .*This may take some time',
]
xfail_strict = true
markers = ["slow: marks tests as slow (deselect with '-m \"not slow\"')"]
Expand Down
8 changes: 4 additions & 4 deletions tests/expr_and_series/arithmetic_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,10 @@ def test_truediv_same_dims(constructor_eager: Any, request: Any) -> None:
request.applymarker(pytest.mark.xfail)
s_left = nw.from_native(constructor_eager({"a": [1, 2, 3]}), eager_only=True)["a"]
s_right = nw.from_native(constructor_eager({"a": [2, 2, 1]}), eager_only=True)["a"]
result = (s_left / s_right).to_list()
assert result == [0.5, 1.0, 3.0]
result = (s_left.__rtruediv__(s_right)).to_list()
assert result == [2, 1, 1 / 3]
result = s_left / s_right
compare_dicts({"a": result}, {"a": [0.5, 1.0, 3.0]})
result = s_left.__rtruediv__(s_right)
compare_dicts({"a": result}, {"a": [2, 1, 1 / 3]})


@pytest.mark.slow()
Expand Down
8 changes: 4 additions & 4 deletions tests/expr_and_series/cat/get_categories_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ def test_get_categories(request: Any, constructor_eager: Any) -> None:
result_expr = df.select(nw.col("a").cat.get_categories())
compare_dicts(result_expr, expected)

result_series = df["a"].cat.get_categories().to_list()
assert set(result_series) == set(expected["a"])
result_series = df["a"].cat.get_categories()
compare_dicts({"a": result_series}, expected)


def test_get_categories_pyarrow() -> None:
Expand All @@ -41,5 +41,5 @@ def test_get_categories_pyarrow() -> None:
result_expr = df.select(nw.col("a").cat.get_categories())
compare_dicts(result_expr, expected)

result_series = df["a"].cat.get_categories().to_list()
assert result_series == expected["a"]
result_series = df["a"].cat.get_categories()
compare_dicts({"a": result_series}, expected)
4 changes: 1 addition & 3 deletions tests/expr_and_series/dt/datetime_duration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ def test_duration_attributes(
expected_b: list[int],
expected_c: list[int],
) -> None:
if "dask_lazy" in str(constructor) or (
parse_version(pd.__version__) < (2, 2) and "pandas_pyarrow" in str(constructor)
):
if parse_version(pd.__version__) < (2, 2) and "pandas_pyarrow" in str(constructor):
request.applymarker(pytest.mark.xfail)

df = nw.from_native(constructor(data))
Expand Down
Loading

0 comments on commit 3b37c5a

Please sign in to comment.