REGR: fix recursion error in GeoDataFrame constructor with MultiIndex (#2497)

* REGR: fix recursion error in GeoDataFrame constructor with MultiIndex

* Add test for pivot (GH-2057)

* add changelog

Co-authored-by: Matt Richards <45483497+m-richards@users.noreply.github.com>
This commit is contained in:
Joris Van den Bossche
2022-07-19 08:47:12 +10:00
committed by GitHub
co-authored by Matt Richards
parent a844ee90b9
commit 5c8ae832e0
5 changed files with 43 additions and 1 deletions
+4
View File
@@ -15,6 +15,10 @@ Deprecations and compatibility notes:
Bug fixes:
- Fix regression (RecursionError) in reshape methods such as ``unstack()``
and ``pivot()`` involving MultiIndex, or GeoDataFrame construction with
MultiIndex (#2486).
Notes on (optional) dependencies:
Version 0.11 (June 20, 2022)
+5 -1
View File
@@ -148,7 +148,11 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
if crs is not None and data.crs != crs:
raise ValueError(crs_mismatch_error)
if geometry is None and "geometry" in self.columns:
if (
geometry is None
and self.columns.nlevels == 1
and "geometry" in self.columns
):
# Check for multiple columns with name "geometry". If there are,
# self["geometry"] is a gdf and constructor gets recursively recalled
# by pandas internals trying to access this
+19
View File
@@ -1220,6 +1220,25 @@ class TestConstructor:
with pytest.raises(ValueError):
GeoDataFrame(df3, geometry="geom")
@pytest.mark.parametrize("dtype", ["geometry", "object"])
def test_multiindex_with_geometry_label(self, dtype):
# DataFrame with MultiIndex where "geometry" label corresponds to
# multiple columns
df = pd.DataFrame([[Point(0, 0), Point(1, 1)], [Point(2, 2), Point(3, 3)]])
df = df.astype(dtype)
df.columns = pd.MultiIndex.from_product([["geometry"], [0, 1]])
# don't error in constructor
gdf = GeoDataFrame(df)
# Getting the .geometry column gives GeoDataFrame for both columns
# (but with first MultiIndex level removed)
# TODO should this give an error instead?
result = gdf.geometry
assert result.shape == gdf.shape
assert result.columns.tolist() == [0, 1]
assert_frame_equal(result, gdf["geometry"])
result = gdf[["geometry"]]
assert_frame_equal(result, gdf if dtype == "geometry" else pd.DataFrame(gdf))
def test_geodataframe_crs():
gdf = GeoDataFrame(columns=["geometry"])
+5
View File
@@ -289,6 +289,11 @@ def test_expanddim_in_unstack():
else: # pandas GH37369, unstack doesn't call finalize
assert unstack._geometry_column_name == "geometry"
# https://github.com/geopandas/geopandas/issues/2486
s.name = "geometry"
unstack = s.unstack()
assert_object(unstack, GeoDataFrame, None, None)
# indexing / constructor_sliced tests
+10
View File
@@ -657,6 +657,16 @@ def test_df_apply_returning_series(df):
assert_series_equal(result, df["value1"].rename(None))
def test_pivot(df):
# https://github.com/geopandas/geopandas/issues/2057
# pivot failing due to creating a MultiIndex
result = df.pivot(columns="value1")
expected = GeoDataFrame(pd.DataFrame(df).pivot(columns="value1"))
# TODO assert_geodataframe_equal crashes
assert isinstance(result, GeoDataFrame)
assert_frame_equal(result, expected)
def test_preserve_attrs(df):
# https://github.com/geopandas/geopandas/issues/1654
df.attrs["name"] = "my_name"