Repository: geopandas/geopandas
Pull request #3339 (2024-06-13 11:48:26)

CI: Postgis CI ignores exit codes
I was looking into #3338 and noticed that https://github.com/geopandas/geopandas/actions/runs/9483017108/job/26129164190 is passing, even though the postgis tests are failing. There was a typo added in #3328 that needs fixing is all.
Aiming to make sure the tests fail before I get them passing.

Here's the now failing tests: https://github.com/geopandas/geopandas/actions/runs/9499054652/job/26179125647?pr=3339 - we were swallowing the exit code with some extra bash stuff to check if all the tests were skipped (I guess this is to prevent the tests silently passing if postgis isn't installed)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 741b90c8..eebf28ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,9 +6,9 @@ Notes on dependencies:
 
 - GeoPandas 1.0 drops support for shapely<2 and PyGEOS. The only geometry engine that is
   currently supported is shapely >= 2. As a consequence, spatial indexing based on the
-  rtree package has also been removed. (#3035)
+  rtree package has also been removed (#3035).
 - The I/O engine now defaults to Pyogrio which is now installed with GeoPandas instead
-  of Fiona. (#3223)
+  of Fiona (#3223).
 
 New methods:
 
@@ -56,19 +56,22 @@ New features and improvements:
 - Added support to ``to_parquet`` and ``read_parquet`` for writing and reading files
   using the GeoArrow-based native geometry encoding of GeoParquet 1.1 (#3253, #3275).
 - Add `sort` keyword to `clip` method for GeoSeries and GeoDataFrame to allow optional
-  preservation of the original order of observations. (#3233)
+  preservation of the original order of observations (#3233).
 - Added `show_bbox`, `drop_id` and `to_wgs84` arguments to allow further customization of
-  `GeoSeries.to_json` (#3226)
+  `GeoSeries.to_json` (#3226).
 - `explore` now supports `GeoDataFrame`s with additional columns containing datetimes, uuids and
   other non JSON serializable objects (#3261).
 - The `GeoSeries.fillna` method now supports the `limit` keyword (#3290).
 - Added support for `bbox` covering encoding in geoparquet. Can filter reading of parquet
-files based on a bounding box, and write out a bounding box column to parquet files (#3282)
+files based on a bounding box, and write out a bounding box column to parquet files (#3282).
 - `align` keyword in binary methods now defaults to `None`, treated as True. Explicit True
-  will silence the warning about mismachted indices. (#3212)
+  will silence the warning about mismatched indices (#3212).
 - `GeoSeries.set_crs` can now be used to remove CRS information by passing
-  `crs=None, allow_override=True`. (#3316)
+  `crs=None, allow_override=True` (#3316).
 - Added ``autolim`` keyword argument to ``GeoSeries.plot()`` and ``GeoDataFrame.plot()`` (#2817).
+- Updated documentation to clarify that passing a named (Geo)Series as the `geometry`
+  argument to the GeoDataFrame constructor will not use the name but will always  
+  produce a GeoDataFrame with an active geometry column named "geometry" (#3337).
 
 Backwards incompatible API changes:
 
@@ -84,7 +87,12 @@ Backwards incompatible API changes:
   the previous active geometry column name. This means that if the new and old names are
   different, then both columns will be preserved in the GeoDataFrame. To replicate the previous
   behaviour, you can instead call `gdf.set_geometry(ser.rename(gdf.active_geometry_name))` (#3237).
-- `delaunay_triangles` now considers all geometries together when creating the Delaunay trianguation
+  Note that this behaviour change does not affect the `GeoDataframe` constructor, passing a named 
+  GeoSeries `ser` to `GeoDataFrame(df, geometry=ser)` will always produce a GeoDataFrame with a
+  geometry column named "geometry" to preserve backwards compatibility. If you would like to
+  instead propagate the name of `ser` when constructing a GeoDataFrame, you can instead call
+  `df.set_geometry(ser)` or `GeoDataFrame(df, geometry=ser).rename_geometry(ser.name)` (#3337).
+- `delaunay_triangles` now considers all geometries together when creating the Delaunay triangulation
   instead of performing the operation element-wise. If you want to generate Delaunay
   triangles for each geometry separately, use ``shapely.delaunay_triangles`` instead. (#3273)
 - Reading a data source that does not have a geometry field using ``read_file``
diff --git a/doc/source/docs/user_guide/projections.rst b/doc/source/docs/user_guide/projections.rst
index b589c10a..fbba9c15 100644
--- a/doc/source/docs/user_guide/projections.rst
+++ b/doc/source/docs/user_guide/projections.rst
@@ -252,7 +252,7 @@ One possible way to find out the EPSG code is using pyproj for this:
 value if the match is not perfect)
 
 Further, on websites such as `Spatial Reference <https://spatialreference.org/>`__
-and `epsg.io <https://epsg.io/>`__ the descriptions of many CRS can be found
+and `epsg.org <https://epsg.org/>`__ the descriptions of many CRS can be found
 including their EPSG codes and proj4 string definitions.
 
 **Other formats**
@@ -363,7 +363,7 @@ can be a reason that the CRS object is not equal to the expected EPSG code.
 
 Consider the following example of a Canadian projected CRS EPSG:2953. When
 constructing the CRS object from the WKT string as provided on
-`EPSG:2953 <https://epsg.io/2953>`__:
+`EPSG:2953 <https://spatialreference.org/ref/epsg/2953/>`__:
 
 .. code-block:: python
 
diff --git a/doc/source/gallery/plotting_basemap_background.ipynb b/doc/source/gallery/plotting_basemap_background.ipynb
index 6b0ddc12..77da1a89 100644
--- a/doc/source/gallery/plotting_basemap_background.ipynb
+++ b/doc/source/gallery/plotting_basemap_background.ipynb
@@ -57,7 +57,7 @@
     "coordinate reference systems (CRS) of the tiles and the data match.\n",
     "Web map tiles are typically provided in\n",
     "[Web Mercator](https://en.wikipedia.org/wiki/Web_Mercator>)\n",
-    "([EPSG 3857](https://epsg.io/3857)), so let us first check what\n",
+    "([EPSG 3857](https://spatialreference.org/ref/epsg/3857/)), so let us first check what\n",
     "CRS our NYC boroughs are in:"
    ]
   },
diff --git a/doc/source/gallery/polygon_plotting_with_folium.ipynb b/doc/source/gallery/polygon_plotting_with_folium.ipynb
index 1da13782..b6f7b68a 100644
--- a/doc/source/gallery/polygon_plotting_with_folium.ipynb
+++ b/doc/source/gallery/polygon_plotting_with_folium.ipynb
@@ -81,7 +81,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "The [epsg:2263](https://epsg.io/2263) crs is a projected coordinate reference system with linear units (ft in this case).\n",
+    "The [EPSG:2263](https://spatialreference.org/ref/epsg/2263/) crs is a projected coordinate reference system with linear units (ft in this case).\n",
     "As folium (i.e. leaflet.js) by default accepts values of latitude and longitude (angular units) as input, we need to project the geometry to a geographic coordinate system first."
    ]
   },
diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py
index 699ed0aa..2b35629d 100644
--- a/geopandas/geodataframe.py
+++ b/geopandas/geodataframe.py
@@ -87,9 +87,13 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
         Coordinate Reference System of the geometry objects. Can be anything accepted by
         :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
         such as an authority string (eg "EPSG:4326") or a WKT string.
-    geometry : str or array (optional)
-        If str, column to use as geometry. If array, will be set as 'geometry'
-        column on GeoDataFrame.
+    geometry : str or array-like (optional)
+        If str, column to use as active geometry column. If array-like, it will be
+        added as new column named 'geometry' column on GeoDataFrame and set as the
+        active geometry column. Note that if ``geometry`` is a (Geo)Series with a
+        name, the name will not be used, a column named "geometry" will still be
+        added. To preserve the name, you can use :meth:`~GeoDataFrame.rename_geometry`
+        to update the geometry column name.
 
     Examples
     --------
@@ -194,6 +198,11 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
             ):
                 raise ValueError(crs_mismatch_error)
 
+            if hasattr(geometry, "name") and geometry.name not in ("geometry", None):
+                # __init__ always creates geometry col named "geometry"
+                # rename as `set_geometry` respects the given series name
+                geometry = geometry.rename("geometry")
+
             self.set_geometry(geometry, inplace=True, crs=crs)
 
         if geometry is None and crs:


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 83303400..4e419a47 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -101,6 +101,7 @@ jobs:
         run: |
           conda install postgis -c conda-forge
           sh ci/scripts/setup_postgres.sh
+          set -o pipefail
           pytest -v -r fEs --color=yes --cov=geopandas --cov-append --cov-report term-missing --cov-report xml geopandas/io/tests/test_sql.py | tee /dev/stderr | if grep SKIPPED >/dev/null;then echo "TESTS SKIPPED, FAILING" && exit 1;fi
 
       - name: Test docstrings
diff --git a/geopandas/io/tests/test_sql.py b/geopandas/io/tests/test_sql.py
index b07ba2d6..5832bcbf 100644
--- a/geopandas/io/tests/test_sql.py
+++ b/geopandas/io/tests/test_sql.py
@@ -780,7 +780,7 @@ class TestIO:
         # of appending dataframes to postgis that have no CRS as postgis
         # no CRS value is 0.
         engine = engine_postgis
-        df_nybb = df_nybb.set_.crs(None, allow_override=True)
+        df_nybb = df_nybb.set_crs(None, allow_override=True)
         table = "nybb"
 
         write_postgis(df_nybb, con=engine, name=table, if_exists="replace")
diff --git a/geopandas/tests/test_geodataframe.py b/geopandas/tests/test_geodataframe.py
index 8efb81ab..c9d74b1f 100644
--- a/geopandas/tests/test_geodataframe.py
+++ b/geopandas/tests/test_geodataframe.py
@@ -1323,18 +1323,17 @@ class TestConstructor:
         check_geodataframe(gdf)
         assert list(gdf.columns) == ["geometry", "a"]
 
-    def test_preserve_series_name(self):
+    def test_do_not_preserve_series_name_in_constructor(self):
+        # GH3337
+        # GeoDataFrame(... geometry=...) should always create geom col "geometry"
         geoms = [Point(1, 1), Point(2, 2), Point(3, 3)]
         gs = GeoSeries(geoms)
         gdf = GeoDataFrame({"a": [1, 2, 3]}, geometry=gs)
-
         check_geodataframe(gdf, geometry_column="geometry")
-
-        geoms = [Point(1, 1), Point(2, 2), Point(3, 3)]
+        # still get "geometry", even with custom geoseries name
         gs = GeoSeries(geoms, name="my_geom")
         gdf = GeoDataFrame({"a": [1, 2, 3]}, geometry=gs)
-
-        check_geodataframe(gdf, geometry_column="my_geom")
+        check_geodataframe(gdf, geometry_column="geometry")
 
     def test_overwrite_geometry(self):
         # GH602