Skip to content

Commit 858deb0

Browse files
NickCrewscpcloud
andauthored
feat(datatypes): allow trailing comma in struct string shorthands (#10393)
Co-authored-by: Phillip Cloud <[email protected]>
1 parent 5c14965 commit 858deb0

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

ibis/expr/datatypes/parse.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,14 @@ def geotype_parser(typ: type[dt.DataType]) -> dt.DataType:
195195
struct = (
196196
spaceless_string("struct")
197197
.then(LANGLE)
198-
.then(parsy.seq(spaceless(FIELD).skip(COLON), ty).sep_by(COMMA))
198+
.then(
199+
parsy.alt(
200+
parsy.seq(spaceless(FIELD).skip(COLON), ty)
201+
.sep_by(COMMA, min=1)
202+
.skip(COMMA.optional()),
203+
parsy.seq(),
204+
)
205+
)
199206
.skip(RANGLE)
200207
.map(dt.Struct.from_tuples)
201208
)

ibis/expr/datatypes/tests/test_parse.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import hypothesis.strategies as st
77
import parsy
88
import pytest
9+
from pytest import param
910

1011
import ibis.expr.datatypes as dt
1112
import ibis.tests.strategies as its
@@ -159,6 +160,34 @@ def test_struct_with_string_types():
159160
)
160161

161162

163+
@pytest.mark.parametrize(
164+
("type_string", "expected_dtype"),
165+
[
166+
("struct<a: int32,>", {"a": dt.int32}),
167+
("struct<a: int32, b: string , >", {"a": dt.int32, "b": dt.string}),
168+
],
169+
ids=["single_field", "multiple_fields"],
170+
)
171+
def test_struct_trailing_comma(type_string, expected_dtype):
172+
result = dt.dtype(type_string)
173+
assert result == dt.Struct(expected_dtype)
174+
175+
176+
@pytest.mark.parametrize(
177+
"invalid_type_string",
178+
[
179+
param("struct<,>", id="missing_key"),
180+
param("struct<a,>", id="missing_colon"),
181+
param("struct<b: ,>", id="missing_value"),
182+
param("struct<c:in,>", id="invalid_type"),
183+
param("struct<a:int,b:int64,,>", id="double_comma"),
184+
],
185+
)
186+
def test_struct_trailing_comma_invalid(invalid_type_string):
187+
with pytest.raises(parsy.ParseError):
188+
dt.dtype(invalid_type_string)
189+
190+
162191
def test_array_with_string_value_types():
163192
assert dt.Array("int32") == dt.Array(dt.int32)
164193
assert dt.Array(dt.Array("array<map<string, double>>")) == (
@@ -293,3 +322,7 @@ def test_parse_null():
293322
@h.given(roundtrippable_dtypes)
294323
def test_parse_dtype_roundtrip(dtype):
295324
assert dt.dtype(str(dtype)) == dtype
325+
326+
327+
def test_parse_empty_struct():
328+
assert dt.dtype("struct<>") == dt.Struct({})

0 commit comments

Comments
 (0)