Skip to content

Commit 5df2022

Browse files
committed
feat(datatype): implement Mapping abstract base class for StructType
1 parent a8d3007 commit 5df2022

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

ibis/expr/datatypes/core.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import numbers
44
from abc import abstractmethod
5+
from collections.abc import Iterator, Mapping
56
from typing import Any, Iterable, NamedTuple
67

78
import numpy as np
@@ -639,7 +640,7 @@ def to_integer_type(self):
639640

640641

641642
@public
642-
class Struct(DataType):
643+
class Struct(DataType, Mapping):
643644
"""Structured values."""
644645

645646
fields = frozendict_of(instance_of(str), datatype)
@@ -677,6 +678,12 @@ def types(self) -> tuple[DataType, ...]:
677678
"""Return the types of the struct's fields."""
678679
return tuple(self.fields.values())
679680

681+
def __len__(self) -> int:
682+
return len(self.fields)
683+
684+
def __iter__(self) -> Iterator[str]:
685+
return iter(self.fields)
686+
680687
def __getitem__(self, key: str) -> DataType:
681688
return self.fields[key]
682689

ibis/tests/expr/test_datatypes.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,45 @@ def test_struct_with_string_types():
141141
)
142142

143143

144+
def test_struct_mapping_api():
145+
s = dt.Struct(
146+
{
147+
'a': 'map<double, string>',
148+
'b': 'array<map<string, array<int32>>>',
149+
'c': 'array<string>',
150+
'd': 'int8',
151+
}
152+
)
153+
154+
assert s['a'] == dt.Map(dt.double, dt.string)
155+
assert s['b'] == dt.Array(dt.Map(dt.string, dt.Array(dt.int32)))
156+
assert s['c'] == dt.Array(dt.string)
157+
assert s['d'] == dt.int8
158+
159+
assert 'a' in s
160+
assert 'e' not in s
161+
assert len(s) == 4
162+
assert tuple(s) == s.names
163+
assert tuple(s.keys()) == s.names
164+
assert tuple(s.values()) == s.types
165+
assert tuple(s.items()) == tuple(zip(s.names, s.types))
166+
167+
s1 = s.copy()
168+
s2 = dt.Struct(
169+
{
170+
'a': 'map<double, string>',
171+
'b': 'array<map<string, array<int32>>>',
172+
'c': 'array<string>',
173+
}
174+
)
175+
assert s == s1
176+
assert s != s2
177+
178+
# doesn't support item assignment
179+
with pytest.raises(TypeError):
180+
s['e'] = dt.int8
181+
182+
144183
@pytest.mark.parametrize(
145184
'case',
146185
[

0 commit comments

Comments
 (0)