Repository: geopandas/geopandas

Issue:
BUG: behaviour of `gdf.geometry` is inconsistent when `"geometry"` is not the active geometry column name
The `.geometry` attribute of a GeoDataFrame is special in that it always should return the active geometry column of a geodataframe, in the same way that `df.index` or `df.columns` is special in pandas. However unlike those two cases, we need to deal with the active geometry column being missing, as it is one of the columns, rather than being orthogonal to them. To me, it seems clear that `.geometry` should either return the active geometry or raise an attribute error - however it is currently possible for it to return a column named `geometry` which is not the active geometry column:

> While looking at the above example, I was also wondering, if the geom2 and geometry names are switched (geom2 is active) and then drop geom2, should `.geometry` then raise the error? Currently we then return the non-active "geometry" column:


```
In [25]: gdf = gpd.read_file(gpd.datasets.get_path("nybb"))

In [26]: gdf['geom2'] = gdf.geometry

In [27]: gdf2 = gdf.set_geometry("geom2")

In [28]: gdf3 = gdf2.loc[:, ["BoroCode", "BoroName", "geometry"]]

In [29]: gdf3._geometry_column_name
Out[29]: 'geom2'

In [30]: gdf3.geometry
Out[30]: 
0    MULTIPOLYGON (((970217.022 145643.332, 970227....
1    MULTIPOLYGON (((1029606.077 156073.814, 102957...
2    MULTIPOLYGON (((1021176.479 151374.797, 102100...
3    MULTIPOLYGON (((981219.056 188655.316, 980940....
4    MULTIPOLYGON (((1012821.806 229228.265, 101278...
Name: geometry, dtype: geometry
```

(same happens in case of `__getitem__` when `_geometry_column_name` of `gdf3` is None)

_Originally posted by @jorisvandenbossche in https://github.com/geopandas/geopandas/issues/2517#issuecomment-1212855687_
      
BUG: behaviour of `gdf.geometry` is inconsistent when `"geometry"` is not the active geometry column name
The `.geometry` attribute of a GeoDataFrame is special in that it always should return the active geometry column of a geodataframe, in the same way that `df.index` or `df.columns` is special in pandas. However unlike those two cases, we need to deal with the active geometry column being missing, as it is one of the columns, rather than being orthogonal to them. To me, it seems clear that `.geometry` should either return the active geometry or raise an attribute error - however it is currently possible for it to return a column named `geometry` which is not the active geometry column:

> While looking at the above example, I was also wondering, if the geom2 and geometry names are switched (geom2 is active) and then drop geom2, should `.geometry` then raise the error? Currently we then return the non-active "geometry" column:


```
In [25]: gdf = gpd.read_file(gpd.datasets.get_path("nybb"))

In [26]: gdf['geom2'] = gdf.geometry

In [27]: gdf2 = gdf.set_geometry("geom2")

In [28]: gdf3 = gdf2.loc[:, ["BoroCode", "BoroName", "geometry"]]

In [29]: gdf3._geometry_column_name
Out[29]: 'geom2'

In [30]: gdf3.geometry
Out[30]: 
0    MULTIPOLYGON (((970217.022 145643.332, 970227....
1    MULTIPOLYGON (((1029606.077 156073.814, 102957...
2    MULTIPOLYGON (((1021176.479 151374.797, 102100...
3    MULTIPOLYGON (((981219.056 188655.316, 980940....
4    MULTIPOLYGON (((1012821.806 229228.265, 101278...
Name: geometry, dtype: geometry
```

(same happens in case of `__getitem__` when `_geometry_column_name` of `gdf3` is None)

_Originally posted by @jorisvandenbossche in https://github.com/geopandas/geopandas/issues/2517#issuecomment-1212855687_
      


Discussion:

Resolving patch:
diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py
--- a/geopandas/geodataframe.py
+++ b/geopandas/geodataframe.py
@@ -126,6 +126,9 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
     # TODO: remove "_crs" in 0.12
     _metadata = ["_crs", "_geometry_column_name"]
 
+    _internal_names = DataFrame._internal_names + ["geometry"]
+    _internal_names_set = set(_internal_names)
+
     _geometry_column_name = DEFAULT_GEO_COLUMN_NAME
 
     def __init__(self, data=None, *args, geometry=None, crs=None, **kwargs):


Test patch:
diff --git a/geopandas/tests/test_geodataframe.py b/geopandas/tests/test_geodataframe.py
--- a/geopandas/tests/test_geodataframe.py
+++ b/geopandas/tests/test_geodataframe.py
@@ -361,6 +361,17 @@ def test_get_geometry_invalid(self):
         with pytest.raises(AttributeError, match=msg_no_other_geo_cols):
             GeoDataFrame().geometry
 
+    def test_get_geometry_geometry_inactive(self):
+        # https://github.com/geopandas/geopandas/issues/2574
+        df = self.df.assign(geom2=self.df.geometry).set_geometry("geom2")
+        df = df.loc[:, ["BoroName", "geometry"]]
+        assert df._geometry_column_name == "geom2"
+        msg_geo_col_missing = "is not present. "
+        # Check that df.geometry raises if active geometry column is missing,
+        # it should not fall back to column named "geometry"
+        with pytest.raises(AttributeError, match=msg_geo_col_missing):
+            df.geometry
+
     def test_align(self):
         df = self.df2