Skip to content

Commit

Permalink
feat(api): support abstract type names in selectors.of_type
Browse files Browse the repository at this point in the history
  • Loading branch information
jcrist committed May 11, 2023
1 parent 6f71735 commit f6d2d56
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 5 deletions.
35 changes: 30 additions & 5 deletions ibis/selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,17 +197,42 @@ def of_type(dtype: dt.DataType | str | type[dt.DataType]) -> Predicate:
>>> expr.columns
['siblings']
Select by category of `DataType` by passing the `DataType` class
>>> expr = t.select(s.of_type(dt.Array))
>>> expr.columns
Abstract/unparametrized types may also be specified by their string name
(e.g. "integer" for any integer type), or by passing in a `DataType` class
instead. The following options are equivalent.
>>> expr1 = t.select(s.of_type("array"))
>>> expr2 = t.select(s.of_type(dt.Array))
>>> expr1.equals(expr2)
True
>>> expr2.columns
['siblings', 'parents']
See Also
--------
[`numeric`][ibis.selectors.numeric]
"""
if inspect.isclass(dtype):
if isinstance(dtype, str):
# A mapping of abstract or parametric types, to allow selecting all
# subclasses/parametrizations of these types, rather than only a
# specific instance.
abstract = {
"array": dt.Array,
"decimal": dt.Decimal,
"floating": dt.Floating,
"geospatial": dt.GeoSpatial,
"integer": dt.Integer,
"map": dt.Map,
"numeric": dt.Numeric,
"struct": dt.Struct,
"temporal": dt.Temporal,
}
if cls := abstract.get(dtype.lower()):
predicate = lambda col: isinstance(col.type(), cls)
else:
dtype = dt.dtype(dtype)
predicate = lambda col: col.type() == dtype
elif inspect.isclass(dtype):
predicate = lambda col: isinstance(col.type(), dtype)
else:
dtype = dt.dtype(dtype)
Expand Down
33 changes: 33 additions & 0 deletions ibis/tests/expr/test_selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,39 @@ def test_of_type(t, obj, expected):
assert t.select(s.of_type(obj)).equals(t.select(*expected))


@pytest.mark.parametrize(
"name,expected",
[
("array", ["c_array"]),
("decimal", ["c_dec52"]),
("floating", ["c_f32", "c_f64"]),
("geospatial", ["c_point"]),
("integer", ["c_i32", "c_u64"]),
("map", ["c_map"]),
("numeric", ["c_dec52", "c_f32", "c_f64", "c_i32", "c_u64"]),
("struct", ["c_struct"]),
("temporal", ["c_timestamp", "c_date"]),
],
)
def test_of_type_abstract(name, expected):
t = ibis.table(
dict(
c_array="array<int>",
c_dec52="decimal(5, 2)",
c_f32="float32",
c_f64="float64",
c_point="point",
c_i32="int32",
c_u64="uint64",
c_map="map<string,int>",
c_struct="struct<a:int>",
c_timestamp="timestamp",
c_date="date",
)
)
assert t.select(s.of_type(name)).equals(t.select(*expected))


@pytest.mark.parametrize(
("prefixes", "expected"),
[("a", ("a",)), (("a", "e"), ("a", "e"))],
Expand Down

0 comments on commit f6d2d56

Please sign in to comment.