Skip to content

Commit e32e139

Browse files
committed
Merge remote-tracking branch 'upstream/main' into df-repr-html
2 parents f73d564 + 79c00c0 commit e32e139

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+721
-454
lines changed

.github/workflows/pytest-pyspark.yml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ name: PyTest PySpark constructor
22

33
on:
44
pull_request:
5-
types: [opened, labeled, synchronize] # Triggers on PR creation, updates, and label changes
5+
paths:
6+
- narwhals/_expression_parsing.py
7+
- narwhals/_spark_like/**
8+
- narwhals/_sql/**
9+
schedule:
10+
- cron: 0 12 * * 0 # Sunday at mid-day
611

712
env:
813
PY_COLORS: 1
@@ -11,10 +16,9 @@ env:
1116
jobs:
1217

1318
pytest-pyspark-constructor:
14-
if: ${{ contains(github.event.pull_request.labels.*.name, 'pyspark') || contains(github.event.pull_request.labels.*.name, 'spark-like') || contains(github.event.pull_request.labels.*.name, 'release')}}
1519
strategy:
1620
matrix:
17-
python-version: ["3.10", "3.11"]
21+
python-version: ["3.11"]
1822
os: [ubuntu-latest]
1923
runs-on: ${{ matrix.os }}
2024
steps:
@@ -39,10 +43,9 @@ jobs:
3943

4044

4145
pytest-pyspark-connect-constructor:
42-
if: ${{ contains(github.event.pull_request.labels.*.name, 'pyspark-connect') || contains(github.event.pull_request.labels.*.name, 'release') }}
4346
strategy:
4447
matrix:
45-
python-version: ["3.10", "3.11"]
48+
python-version: ["3.11"]
4649
os: [ubuntu-latest]
4750
env:
4851
SPARK_VERSION: 3.5.5

.pre-commit-config.yaml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,15 @@ repos:
2626
hooks:
2727
- id: flake8
2828
additional_dependencies: [darglint==1.8.1, Flake8-pyproject]
29-
entry: flake8 --select DAR --ignore DAR101,DAR402,DAR401
29+
entry: flake8 --select DAR --ignore DAR101,DAR401,DAR402
3030
exclude: |
3131
(?x)^(
3232
tests/.*|
3333
# TODO: gradually enable
34-
narwhals/series\.py|
35-
# TODO: gradually enable
36-
narwhals/dataframe\.py|
37-
# TODO: gradually enable
3834
narwhals/dependencies\.py|
39-
# private, so less urgent to document too well
35+
# Private, so less urgent to document too well
4036
narwhals/_.*|
37+
# Internal use only, less urgent
4138
^utils/.*|
4239
# Soft-deprecated, so less crucial to document so carefully
4340
narwhals/stable/v1/.*

docs/api-reference/series.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
- exp
3030
- fill_null
3131
- filter
32+
- from_numpy
3233
- gather_every
3334
- head
3435
- hist

narwhals/_compliant/series.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,15 +285,15 @@ def hist_from_bin_count(
285285
...
286286

287287
@property
288-
def str(self) -> Any: ...
288+
def str(self) -> StringNamespace[Self]: ...
289289
@property
290-
def dt(self) -> Any: ...
290+
def dt(self) -> DateTimeNamespace[Self]: ...
291291
@property
292-
def cat(self) -> Any: ...
292+
def cat(self) -> CatNamespace[Self]: ...
293293
@property
294-
def list(self) -> Any: ...
294+
def list(self) -> ListNamespace[Self]: ...
295295
@property
296-
def struct(self) -> Any: ...
296+
def struct(self) -> StructNamespace[Self]: ...
297297

298298

299299
class EagerSeries(CompliantSeries[NativeSeriesT], Protocol[NativeSeriesT]):

narwhals/_duckdb/expr.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -292,23 +292,6 @@ def window_f(df: DuckDBLazyFrame, inputs: DuckDBWindowInputs) -> list[Expression
292292
version=self._version,
293293
)
294294

295-
def log(self, base: float) -> Self:
296-
def _log(expr: Expression) -> Expression:
297-
log = F("log", expr)
298-
return (
299-
when(expr < lit(0), lit(float("nan")))
300-
.when(expr == lit(0), lit(float("-inf")))
301-
.otherwise(log / F("log", lit(base)))
302-
)
303-
304-
return self._with_elementwise(_log)
305-
306-
def sqrt(self) -> Self:
307-
def _sqrt(expr: Expression) -> Expression:
308-
return when(expr < lit(0), lit(float("nan"))).otherwise(F("sqrt", expr))
309-
310-
return self._with_elementwise(_sqrt)
311-
312295
@property
313296
def str(self) -> DuckDBExprStringNamespace:
314297
return DuckDBExprStringNamespace(self)

narwhals/_duckdb/namespace.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,15 @@ def _function(self, name: str, *args: Expression) -> Expression: # type: ignore
6363
def _lit(self, value: Any) -> Expression:
6464
return lit(value)
6565

66-
def _when(self, condition: Expression, value: Expression) -> Expression:
67-
return when(condition, value)
66+
def _when(
67+
self,
68+
condition: Expression,
69+
value: Expression,
70+
otherwise: Expression | None = None,
71+
) -> Expression:
72+
if otherwise is None:
73+
return when(condition, value)
74+
return when(condition, value).otherwise(otherwise)
6875

6976
def _coalesce(self, *exprs: Expression) -> Expression:
7077
return CoalesceOperator(*exprs)

narwhals/_exceptions.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from __future__ import annotations
2+
3+
from warnings import warn
4+
5+
6+
def find_stacklevel() -> int:
7+
"""Find the first place in the stack that is not inside narwhals.
8+
9+
Returns:
10+
Stacklevel.
11+
12+
Taken from:
13+
https://github.com/pandas-dev/pandas/blob/ab89c53f48df67709a533b6a95ce3d911871a0a8/pandas/util/_exceptions.py#L30-L51
14+
"""
15+
import inspect
16+
from pathlib import Path
17+
18+
import narwhals as nw
19+
20+
pkg_dir = str(Path(nw.__file__).parent)
21+
22+
# https://stackoverflow.com/questions/17407119/python-inspect-stack-is-slow
23+
frame = inspect.currentframe()
24+
n = 0
25+
try:
26+
while frame:
27+
fname = inspect.getfile(frame)
28+
if fname.startswith(pkg_dir) or (
29+
(qualname := getattr(frame.f_code, "co_qualname", None))
30+
# ignore @singledispatch wrappers
31+
and qualname.startswith("singledispatch.")
32+
):
33+
frame = frame.f_back
34+
n += 1
35+
else: # pragma: no cover
36+
break
37+
else: # pragma: no cover
38+
pass
39+
finally:
40+
# https://docs.python.org/3/library/inspect.html
41+
# > Though the cycle detector will catch these, destruction of the frames
42+
# > (and local variables) can be made deterministic by removing the cycle
43+
# > in a finally clause.
44+
del frame
45+
return n
46+
47+
48+
def issue_deprecation_warning(message: str, _version: str) -> None: # pragma: no cover
49+
"""Issue a deprecation warning.
50+
51+
Arguments:
52+
message: The message associated with the warning.
53+
_version: Narwhals version when the warning was introduced. Just used for internal
54+
bookkeeping.
55+
"""
56+
warn(message=message, category=DeprecationWarning, stacklevel=find_stacklevel())
57+
58+
59+
def issue_warning(message: str, category: type[Warning]) -> None:
60+
warn(message=message, category=category, stacklevel=find_stacklevel())

narwhals/_expression_parsing.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Utilities for expression parsing
22
# Useful for backends which don't have any concept of expressions, such
33
# and pandas or PyArrow.
4+
# ! Any change to this module will trigger the pyspark and pyspark-connect tests in CI
45
from __future__ import annotations
56

67
from enum import Enum, auto

narwhals/_ibis/expr.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -324,23 +324,6 @@ def _rank(expr: ir.Column) -> ir.Column:
324324

325325
return self._with_callable(_rank)
326326

327-
def log(self, base: float) -> Self:
328-
def _log(expr: ir.NumericColumn) -> ir.Value:
329-
otherwise = expr.log(cast("ir.NumericValue", lit(base)))
330-
return ibis.cases(
331-
(expr < lit(0), lit(float("nan"))),
332-
(expr == lit(0), lit(float("-inf"))),
333-
else_=otherwise,
334-
)
335-
336-
return self._with_callable(_log)
337-
338-
def sqrt(self) -> Self:
339-
def _sqrt(expr: ir.NumericColumn) -> ir.Value:
340-
return ibis.cases((expr < lit(0), lit(float("nan"))), else_=expr.sqrt())
341-
342-
return self._with_callable(_sqrt)
343-
344327
@property
345328
def str(self) -> IbisExprStringNamespace:
346329
return IbisExprStringNamespace(self)

narwhals/_ibis/namespace.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@ def _function(self, name: str, *args: ir.Value | PythonLiteral) -> ir.Value:
5151
def _lit(self, value: Any) -> ir.Value:
5252
return lit(value)
5353

54-
def _when(self, condition: ir.Value, value: ir.Value) -> ir.Value:
55-
return ibis.cases((condition, value))
54+
def _when(
55+
self, condition: ir.Value, value: ir.Value, otherwise: ir.Expr | None = None
56+
) -> ir.Value:
57+
if otherwise is None:
58+
return ibis.cases((condition, value))
59+
return ibis.cases((condition, value), else_=otherwise) # pragma: no cover
5660

5761
def _coalesce(self, *exprs: ir.Value) -> ir.Value:
5862
return ibis.coalesce(*exprs)

0 commit comments

Comments
 (0)