Skip to content

Commit 337018f

Browse files
committed
docs(api): document more public expression APIs
1 parent e7fabaf commit 337018f

File tree

10 files changed

+191
-61
lines changed

10 files changed

+191
-61
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ repos:
2626
hooks:
2727
- id: ruff
2828
# exclude a file (if configured to do so), even if it's passed in explicitly
29-
args: ["--force-exclude", "--fix"]
29+
args: ["--force-exclude"]
3030
- repo: https://github.com/adrienverge/yamllint
3131
rev: v1.29.0
3232
hooks:

ibis/expr/operations/analytic.py

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -62,53 +62,11 @@ class RankBase(Analytic):
6262

6363
@public
6464
class MinRank(RankBase):
65-
"""Compute position of first element within each equal-value group in sorted order.
66-
67-
Equivalent to SQL's `RANK()`.
68-
69-
Examples
70-
--------
71-
values ranks
72-
1 0
73-
1 0
74-
2 2
75-
2 2
76-
2 2
77-
3 5
78-
79-
Returns
80-
-------
81-
Int64Column
82-
The min rank
83-
"""
84-
8565
arg = rlz.column(rlz.any)
8666

8767

8868
@public
8969
class DenseRank(RankBase):
90-
"""Position of first element within each group of equal values.
91-
92-
Values are returned in sorted order and duplicate values are ignored.
93-
94-
Equivalent to SQL's `DENSE_RANK()`.
95-
96-
Examples
97-
--------
98-
values ranks
99-
1 0
100-
1 0
101-
2 1
102-
2 1
103-
2 1
104-
3 2
105-
106-
Returns
107-
-------
108-
IntegerColumn
109-
The rank
110-
"""
111-
11270
arg = rlz.column(rlz.any)
11371

11472

@@ -168,11 +126,6 @@ def output_dtype(self):
168126

169127
@public
170128
class CumulativeMax(CumulativeOp):
171-
"""Cumulative max.
172-
173-
Requires an order window.
174-
"""
175-
176129
arg = rlz.column(rlz.any)
177130
output_dtype = rlz.dtype_like("arg")
178131

ibis/expr/types/core.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,25 @@ def _repr(self) -> str:
6464
return fmt(self)
6565

6666
def equals(self, other):
67+
"""Return whether this expression is _structurally_ equivalent to `other`.
68+
69+
If you want to produce an equality expression, use `==` syntax.
70+
71+
Parameters
72+
----------
73+
other
74+
Another expression
75+
76+
Examples
77+
--------
78+
>>> t1 = ibis.table(dict(a="int"), name="t")
79+
>>> t2 = ibis.table(dict(a="int"), name="t")
80+
>>> t1.equals(t2)
81+
True
82+
>>> v = ibis.table(dict(a="string"), name="v")
83+
>>> t1.equals(v)
84+
False
85+
"""
6786
if not isinstance(other, Expr):
6887
raise TypeError(
6988
f"invalid equality comparison between Expr and {type(other)}"
@@ -76,9 +95,11 @@ def __bool__(self) -> bool:
7695
__nonzero__ = __bool__
7796

7897
def has_name(self):
98+
"""Check whether this expression has an explicit name."""
7999
return isinstance(self._arg, ops.Named)
80100

81101
def get_name(self):
102+
"""Return the name of this expression."""
82103
return self._arg.name
83104

84105
def _repr_png_(self) -> bytes | None:
@@ -172,7 +193,7 @@ def pipe(self, f, *args: Any, **kwargs: Any) -> Expr:
172193
else:
173194
return f(self, *args, **kwargs)
174195

175-
def op(self) -> ops.Node:
196+
def op(self) -> ops.Node: # noqa: D102
176197
return self._arg
177198

178199
def _find_backends(self) -> tuple[list[BaseBackend], bool]:

ibis/expr/types/generic.py

Lines changed: 120 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ def name(self, name):
5959
return op.to_expr()
6060

6161
# TODO(kszucs): should rename to dtype
62-
def type(self):
62+
def type(self) -> dt.DataType:
63+
"""Return the [DataType] of this expression."""
6364
return self.op().output_dtype
6465

6566
def hash(self, how: str = "fnv") -> ir.IntegerValue:
@@ -482,11 +483,25 @@ def desc(self) -> ir.Value:
482483
return ops.SortKey(self, ascending=False).to_expr()
483484

484485
@util.deprecated(as_of="4.1", removed_in="5.0", instead="use `.as_table()`")
485-
def to_projection(self) -> ir.Table:
486+
def to_projection(self) -> ir.Table: # noqa: D102
486487
return self.as_table()
487488

488489
def as_table(self) -> ir.Table:
489-
"""Promote this value expression to a projection."""
490+
"""Promote the expression to a table.
491+
492+
Returns
493+
-------
494+
Table
495+
A table expression
496+
497+
Examples
498+
--------
499+
>>> t = ibis.table(dict(a="str"), name="t")
500+
>>> expr = t.a.length().name("len").as_table()
501+
>>> expected = t.select(len=t.a.length())
502+
>>> expr.equals(expected)
503+
True
504+
"""
490505
from ibis.expr.analysis import find_immediate_parent_tables
491506

492507
roots = find_immediate_parent_tables(self.op())
@@ -510,6 +525,29 @@ def __rich_console__(self, console, options):
510525
return console.render(repr(self.execute()), options=options)
511526

512527
def as_table(self) -> ir.Table:
528+
"""Promote the scalar expression to a table.
529+
530+
Returns
531+
-------
532+
Table
533+
A table expression
534+
535+
Examples
536+
--------
537+
Promote an aggregation to a table
538+
539+
>>> t = ibis.table(dict(a="str"), name="t")
540+
>>> expr = t.a.length().sum().name("len").as_table()
541+
>>> isinstance(expr, ir.Table)
542+
True
543+
544+
Promote a literal value to a table
545+
546+
>>> import ibis.expr.types as ir
547+
>>> lit = ibis.literal(1).name("a").as_table()
548+
>>> isinstance(lit, ir.Table)
549+
True
550+
"""
513551
from ibis.expr.analysis import (
514552
find_first_base_table,
515553
is_scalar_reduction,
@@ -779,46 +817,121 @@ def value_counts(self, metric_name: str = "count") -> ir.Table:
779817
)
780818

781819
def first(self) -> Column:
820+
"""Return the first value of a column.
821+
822+
Equivalent to SQL's `FIRST_VALUE` window function.
823+
"""
782824
return ops.FirstValue(self).to_expr()
783825

784826
def last(self) -> Column:
827+
"""Return the last value of a column.
828+
829+
Equivalent to SQL's `LAST_VALUE` window function.
830+
"""
785831
return ops.LastValue(self).to_expr()
786832

787-
def rank(self) -> Column:
833+
def rank(self) -> ir.IntegerColumn:
834+
"""Compute position of first element within each equal-value group in sorted order.
835+
836+
Equivalent to SQL's `RANK()` window function.
837+
838+
Examples
839+
--------
840+
values ranks
841+
1 0
842+
1 0
843+
2 2
844+
2 2
845+
2 2
846+
3 5
847+
848+
Returns
849+
-------
850+
Int64Column
851+
The min rank
852+
"""
788853
return ops.MinRank(self).to_expr()
789854

790-
def dense_rank(self) -> Column:
855+
def dense_rank(self) -> ir.IntegerColumn:
856+
"""Position of first element within each group of equal values.
857+
858+
Values are returned in sorted order and duplicate values are ignored.
859+
860+
Equivalent to SQL's `DENSE_RANK()`.
861+
862+
Examples
863+
--------
864+
values ranks
865+
1 0
866+
1 0
867+
2 1
868+
2 1
869+
2 1
870+
3 2
871+
872+
Returns
873+
-------
874+
IntegerColumn
875+
The rank
876+
"""
791877
return ops.DenseRank(self).to_expr()
792878

793879
def percent_rank(self) -> Column:
880+
"""Return the relative rank of the values in the column."""
794881
return ops.PercentRank(self).to_expr()
795882

796883
def cume_dist(self) -> Column:
797-
import ibis.expr.operations as ops
798-
884+
"""Return the cumulative distribution over a window."""
799885
return ops.CumeDist(self).to_expr()
800886

801887
def cummin(self) -> Column:
888+
"""Return the cumulative min over a window."""
802889
return ops.CumulativeMin(self).to_expr()
803890

804891
def cummax(self) -> Column:
892+
"""Return the cumulative max over a window."""
805893
return ops.CumulativeMax(self).to_expr()
806894

807895
def lag(
808896
self,
809897
offset: int | ir.IntegerValue | None = None,
810898
default: Value | None = None,
811899
) -> Column:
900+
"""Return the row located at `offset` rows **before** the current row.
901+
902+
Parameters
903+
----------
904+
offset
905+
Index of row to select
906+
default
907+
Value used if no row exists at `offset`
908+
"""
812909
return ops.Lag(self, offset, default).to_expr()
813910

814911
def lead(
815912
self,
816913
offset: int | ir.IntegerValue | None = None,
817914
default: Value | None = None,
818915
) -> Column:
916+
"""Return the row located at `offset` rows **after** the current row.
917+
918+
Parameters
919+
----------
920+
offset
921+
Index of row to select
922+
default
923+
Value used if no row exists at `offset`
924+
"""
819925
return ops.Lead(self, offset, default).to_expr()
820926

821927
def ntile(self, buckets: int | ir.IntegerValue) -> ir.IntegerColumn:
928+
"""Return the integer number of a partitioning of the column values.
929+
930+
Parameters
931+
----------
932+
buckets
933+
Number of buckets to partition into
934+
"""
822935
return ops.NTile(self, buckets).to_expr()
823936

824937
def nth(self, n: int | ir.IntegerValue) -> Column:

ibis/expr/types/groupby.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ def _column_wrapper(self, attr):
8585
return GroupedArray(col, self)
8686

8787
def aggregate(self, metrics=None, **kwds):
88+
"""Compute aggregates over a group by."""
8889
return self.table.aggregate(metrics, by=self.by, having=self._having, **kwds)
8990

9091
agg = aggregate
@@ -290,14 +291,17 @@ def __init__(self, arr, parent):
290291
group_concat = _group_agg_dispatch('group_concat')
291292

292293
def summary(self, exact_nunique=False):
294+
"""Summarize a column.
295+
296+
Parameters
297+
----------
298+
exact_nunique
299+
Whether to compute an exact count distinct.
300+
"""
293301
metric = self.arr.summary(exact_nunique=exact_nunique)
294302
return self.parent.aggregate(metric)
295303

296304

297305
class GroupedNumbers(GroupedArray):
298306
mean = _group_agg_dispatch('mean')
299307
sum = _group_agg_dispatch('sum')
300-
301-
def summary(self, exact_nunique=False):
302-
metric = self.arr.summary(exact_nunique=exact_nunique)
303-
return self.parent.aggregate(metric)

ibis/expr/types/logical.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,23 +78,35 @@ class BooleanScalar(NumericScalar, BooleanValue):
7878
@public
7979
class BooleanColumn(NumericColumn, BooleanValue):
8080
def any(self, where: BooleanValue | None = None) -> BooleanValue:
81+
"""Return whether at least one element is `True`.
82+
83+
Parameters
84+
----------
85+
where
86+
Optional filter for the aggregation
87+
"""
8188
import ibis.expr.analysis as an
8289

8390
return an._make_any(self, ops.Any, where=where)
8491

8592
def notany(self, where: BooleanValue | None = None) -> BooleanValue:
93+
"""Return whether no elements are `True`."""
8694
import ibis.expr.analysis as an
8795

8896
return an._make_any(self, ops.NotAny, where=where)
8997

9098
def all(self, where: BooleanValue | None = None) -> BooleanScalar:
99+
"""Return whether all elements are `True`."""
91100
return ops.All(self, where=where).to_expr()
92101

93102
def notall(self, where: BooleanValue | None = None) -> BooleanScalar:
103+
"""Return whether not all elements are `True`."""
94104
return ops.NotAll(self, where=where).to_expr()
95105

96106
def cumany(self) -> BooleanColumn:
107+
"""Accumulate the `any` aggregate."""
97108
return ops.CumulativeAny(self).to_expr()
98109

99110
def cumall(self) -> BooleanColumn:
111+
"""Accumulate the `all` aggregate."""
100112
return ops.CumulativeAll(self).to_expr()

ibis/expr/types/numeric.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ def mean(
466466
return ops.Mean(self, where=where).to_expr()
467467

468468
def cummean(self) -> NumericColumn:
469+
"""Return the cumulative mean of the input."""
469470
return ops.CumulativeMean(self).to_expr()
470471

471472
def sum(
@@ -487,6 +488,7 @@ def sum(
487488
return ops.Sum(self, where=where).to_expr()
488489

489490
def cumsum(self) -> NumericColumn:
491+
"""Return the cumulative sum of the input."""
490492
return ops.CumulativeSum(self).to_expr()
491493

492494
def bucket(

0 commit comments

Comments
 (0)