Skip to content

Commit 0d32975

Browse files
authored
GH-47380: [Python] Apply maps_as_pydicts to Nested MapScalar Values (#47454)
### Rationale for this change Currently, the `maps_as_pydicts` parameter to `MapScalar.as_py` does not work on nested maps. See below: ``` import pyarrow as pa t = pa.struct([pa.field("x", pa.map_(pa.string(), pa.map_(pa.string(), pa.int8())))]) v = {"x": {"a": {"1": 1}}} s = pa.scalar(v, type=t) print(s.as_py(maps_as_pydicts="strict")) # {'x': {'a': [('1', 1)]}} ``` In this ^ case, I'd want to get the value: `{'x': {'a': {'1': 1}}}`, such that round trips would work as expected. ### What changes are included in this PR? Begin to apply the `maps_as_pydicts` to nested values in map types as well, update relevant test. ### Are these changes tested? Yes ### Are there any user-facing changes? Yes, just a user-facing fix. * GitHub Issue: #47380 Lead-authored-by: Johanna <[email protected]> Co-authored-by: zzkv <[email protected]> Co-authored-by: Johanna <[email protected]> Signed-off-by: Raúl Cumplido <[email protected]>
1 parent bc9746d commit 0d32975

File tree

2 files changed

+35
-3
lines changed

2 files changed

+35
-3
lines changed

python/pyarrow/scalar.pxi

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,7 +1173,10 @@ cdef class MapScalar(ListScalar, Mapping):
11731173
if not maps_as_pydicts:
11741174
return list(self)
11751175
result_dict = {}
1176-
for key, value in self:
1176+
if self.values is None:
1177+
return result_dict
1178+
1179+
for key, value in zip(self.keys(), self.values.field(self.type.item_field.name)):
11771180
if key in result_dict:
11781181
if maps_as_pydicts == "strict":
11791182
raise KeyError(
@@ -1183,7 +1186,7 @@ cdef class MapScalar(ListScalar, Mapping):
11831186
else:
11841187
warnings.warn(
11851188
f"Encountered key '{key}' which was already encountered.")
1186-
result_dict[key] = value
1189+
result_dict[key] = value.as_py(maps_as_pydicts=maps_as_pydicts)
11871190
return result_dict
11881191

11891192
def keys(self):

python/pyarrow/tests/test_scalars.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ def test_map_scalar_as_py_with_custom_field_name():
956956
).as_py() == [("foo", "bar")]
957957

958958

959-
def test_nested_map_types_with_maps_as_pydicts():
959+
def test_map_types_with_maps_as_pydicts():
960960
ty = pa.struct([
961961
pa.field('x', pa.map_(pa.string(), pa.int8())),
962962
pa.field('y', pa.list_(pa.map_(pa.string(), pa.int8()))),
@@ -966,3 +966,32 @@ def test_nested_map_types_with_maps_as_pydicts():
966966
s = pa.scalar(v, type=ty)
967967

968968
assert s.as_py(maps_as_pydicts="strict") == v
969+
970+
971+
def test_nested_map_types_with_maps_as_pydicts():
972+
ty = pa.struct(
973+
[
974+
pa.field('x', pa.map_(pa.string(), pa.map_(pa.string(), pa.int8()))),
975+
pa.field(
976+
'y', pa.list_(pa.map_(pa.string(), pa.map_(pa.string(), pa.int8())))
977+
),
978+
]
979+
)
980+
981+
v = {'x': {'a': {'1': 1}}, 'y': [{'b': {'2': 2}}, {'c': {'3': 3}}]}
982+
s = pa.scalar(v, type=ty)
983+
984+
assert s.as_py(maps_as_pydicts="strict") == v
985+
986+
987+
def test_map_scalar_with_empty_values():
988+
map_type = pa.struct(
989+
[
990+
pa.field('x', pa.map_(pa.string(), pa.string())),
991+
]
992+
)
993+
994+
v = {'x': {}}
995+
s = pa.scalar(v, type=map_type)
996+
997+
assert s.as_py(maps_as_pydicts="strict") == v

0 commit comments

Comments
 (0)