diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 327b88b..f51c004 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -37,10 +37,10 @@ jobs: env: - ci/envs/38-minimal.yaml - ci/envs/39-no-optional-deps.yaml - - ci/envs/38-pd11-defaults.yaml + - ci/envs/38-pd12-defaults.yaml - ci/envs/38-latest-defaults.yaml - ci/envs/38-latest-conda-forge.yaml - - ci/envs/39-pd12-conda-forge.yaml + - ci/envs/39-pd13-conda-forge.yaml - ci/envs/39-latest-conda-forge.yaml - ci/envs/310-latest-conda-forge.yaml - ci/envs/311-latest-conda-forge.yaml @@ -107,7 +107,7 @@ jobs: pytest -v -r a -n auto --color=yes --cov=geopandas --cov-append --cov-report term-missing --cov-report xml geopandas/ - name: Test with PostGIS - if: contains(matrix.env, '39-pd12-conda-forge.yaml') && contains(matrix.os, 'ubuntu') + if: contains(matrix.env, '39-pd13-conda-forge.yaml') && contains(matrix.os, 'ubuntu') env: PGUSER: postgres PGPASSWORD: postgres @@ -119,7 +119,7 @@ jobs: pytest -v -r a --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 - if: contains(matrix.env, '39-pd12-conda-forge.yaml') && contains(matrix.os, 'ubuntu') + if: contains(matrix.env, '39-pd13-conda-forge.yaml') && contains(matrix.os, 'ubuntu') env: USE_PYGEOS: 1 run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 146ed76..904fe2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,14 @@ Bug fixes: - Fix mismatch between geometries and colors in ``plot()`` if an empty or missing geometry is present (#2224) +Notes on (optional) dependencies: + +- GeoPandas 0.13 drops support pandas 1.0.5 (the minimum supported + pandas version is now 1.1). Further, the minimum required versions for the listed + dependencies have now changed to shapely 1.7.1, fiona 1.8.19, pyproj 3.0.1 and + matplotlib 3.3.4 (#2655) + + ## Version 0.12.2 (December 10, 2022) Bug fixes: diff --git a/ci/envs/38-latest-defaults.yaml b/ci/envs/38-latest-defaults.yaml index 8dcf6f3..d995d22 100644 --- a/ci/envs/38-latest-defaults.yaml +++ b/ci/envs/38-latest-defaults.yaml @@ -4,11 +4,11 @@ channels: dependencies: - python=3.8 # required - - numpy=1.21 # pin to < 1.23 for compat with older shapely on defaults channel + - numpy - pandas - shapely - fiona - - pyproj + - pyproj>=3 - geos - packaging # testing diff --git a/ci/envs/38-minimal.yaml b/ci/envs/38-minimal.yaml index b697c63..6a31c91 100644 --- a/ci/envs/38-minimal.yaml +++ b/ci/envs/38-minimal.yaml @@ -5,13 +5,12 @@ channels: dependencies: - python=3.8 # required - - numpy=1.18 - - pandas==1.0.5 - - shapely=1.7 - - fiona=1.8.13.post1 - - pyproj=2.6.1.post1 + - numpy=1.20 + - pandas=1.1 + - shapely=1.7.1 + - fiona=1.8.18 + - pyproj=3.0.1 - packaging - #- pyproj # testing - pytest - pytest-cov @@ -19,10 +18,9 @@ dependencies: - fsspec # optional - rtree - - matplotlib - - matplotlib=3.2 + - matplotlib=3.3.4 - mapclassify=2.4.0 - geopy - SQLalchemy - libspatialite - - pyarrow + - pyarrow=8.0.0 diff --git a/ci/envs/38-pd11-defaults.yaml b/ci/envs/38-pd12-defaults.yaml similarity index 92% rename from ci/envs/38-pd11-defaults.yaml rename to ci/envs/38-pd12-defaults.yaml index eb524c2..9608a37 100644 --- a/ci/envs/38-pd11-defaults.yaml +++ b/ci/envs/38-pd12-defaults.yaml @@ -4,10 +4,10 @@ channels: dependencies: - python=3.8 # required - - pandas=1.1 + - pandas=1.2 - shapely - fiona - - numpy=<1.19 + - numpy=<1.22 - pyproj=3.1.0 #- pyproj - geos diff --git a/ci/envs/39-latest-conda-forge.yaml b/ci/envs/39-latest-conda-forge.yaml index 0dfc4b9..d39c54d 100644 --- a/ci/envs/39-latest-conda-forge.yaml +++ b/ci/envs/39-latest-conda-forge.yaml @@ -4,7 +4,7 @@ channels: dependencies: - python=3.9 # required - - pandas=1.3 + - pandas=1.4 - shapely=2 - geos - cython diff --git a/ci/envs/39-pd12-conda-forge.yaml b/ci/envs/39-pd13-conda-forge.yaml similarity index 88% rename from ci/envs/39-pd12-conda-forge.yaml rename to ci/envs/39-pd13-conda-forge.yaml index 73b62ec..cc038ce 100644 --- a/ci/envs/39-pd12-conda-forge.yaml +++ b/ci/envs/39-pd13-conda-forge.yaml @@ -4,8 +4,8 @@ channels: dependencies: - python=3.9 # required - - pandas=1.2 - - numpy=1.20 # released 1 month after pandas 1.2 + - pandas=1.3 + - numpy=1.21 # released 1 month before pandas 1.3 - shapely - fiona - pyproj diff --git a/doc/source/getting_started/install.rst b/doc/source/getting_started/install.rst index 07ff8d6..66876b8 100644 --- a/doc/source/getting_started/install.rst +++ b/doc/source/getting_started/install.rst @@ -136,10 +136,10 @@ Dependencies Required dependencies: - `numpy`_ -- `pandas`_ (version 1.0 or later) -- `shapely`_ (interface to `GEOS`_; version 1.7 or later) -- `fiona`_ (interface to `GDAL`_; version 1.8 or later) -- `pyproj`_ (interface to `PROJ`_; version 2.6.1 or later) +- `pandas`_ (version 1.1 or later) +- `shapely`_ (interface to `GEOS`_; version 1.7.1 or later) +- `fiona`_ (interface to `GDAL`_; version 1.8.19 or later) +- `pyproj`_ (interface to `PROJ`_; version 3.0.1 or later) - `packaging`_ Further, optional dependencies are: @@ -154,7 +154,7 @@ Further, optional dependencies are: For plotting, these additional packages may be used: -- `matplotlib`_ (>= 3.2.0) +- `matplotlib`_ (>= 3.3.4) - `mapclassify`_ (>= 2.4.0) diff --git a/environment-dev.yml b/environment-dev.yml index 981008f..4bfebfa 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -4,11 +4,11 @@ channels: dependencies: - python # required - - fiona>=1.8 - - pandas>=1.0.0 + - fiona>=1.8.19 + - pandas>=1.1.0 - pygeos - - pyproj>=2.6.1.post1 - - shapely>=1.7 + - pyproj>=3.0.1 + - shapely>=1.7.1 - packaging # testing diff --git a/geopandas/_compat.py b/geopandas/_compat.py index 266da76..1923c13 100644 --- a/geopandas/_compat.py +++ b/geopandas/_compat.py @@ -15,7 +15,6 @@ import shapely.geos # pandas compat # ----------------------------------------------------------------------------- -PANDAS_GE_11 = Version(pd.__version__) >= Version("1.1.0") PANDAS_GE_115 = Version(pd.__version__) >= Version("1.1.5") PANDAS_GE_12 = Version(pd.__version__) >= Version("1.2.0") PANDAS_GE_13 = Version(pd.__version__) >= Version("1.3.0") @@ -255,6 +254,5 @@ except ImportError: # pyproj compat # ----------------------------------------------------------------------------- -PYPROJ_LT_3 = Version(pyproj.__version__) < Version("3") PYPROJ_GE_31 = Version(pyproj.__version__) >= Version("3.1") PYPROJ_GE_32 = Version(pyproj.__version__) >= Version("3.2") diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py index 6b5eb00..1c88562 100644 --- a/geopandas/geodataframe.py +++ b/geopandas/geodataframe.py @@ -1629,10 +1629,6 @@ individually so that features may have different properties together with row/column will be dropped. If False, NA values will also be treated as the key in groups. - This parameter is not supported for pandas < 1.1.0. - A warning will be emitted for earlier pandas versions - if a non-default value is given for this parameter. - .. versionadded:: 0.9.0 **kwargs : Keyword arguments to be passed to the pandas `DataFrameGroupby.agg` method @@ -1677,11 +1673,6 @@ individually so that features may have different properties groupby_kwargs = dict( by=by, level=level, sort=sort, observed=observed, dropna=dropna ) - if not compat.PANDAS_GE_11: - groupby_kwargs.pop("dropna") - - if not dropna: # If they passed a non-default dropna value - warnings.warn("dropna kwarg is not supported for pandas < 1.1.0") # Process non-spatial component data = self.drop(labels=self.geometry.name, axis=1) @@ -1736,8 +1727,6 @@ individually so that features may have different properties multiple rows with single geometries, thereby increasing the vertical size of the GeoDataFrame. - .. note:: ignore_index requires pandas 1.1.0 or newer. - Parameters ---------- column : string, default None @@ -1811,10 +1800,7 @@ individually so that features may have different properties column = self.geometry.name # If the specified column is not a geometry dtype use pandas explode if not isinstance(self[column].dtype, GeometryDtype): - if compat.PANDAS_GE_11: - return super().explode(column, ignore_index=ignore_index, **kwargs) - else: - return super().explode(column, **kwargs) + return super().explode(column, ignore_index=ignore_index, **kwargs) if index_parts is None: if not ignore_index: @@ -2367,6 +2353,3 @@ def _dataframe_set_geometry(self, col, drop=False, inplace=False, crs=None): DataFrame.set_geometry = _dataframe_set_geometry - -if not compat.PANDAS_GE_11: # i.e. on pandas 1.0.x - _geodataframe_constructor_with_fallback._from_axes = GeoDataFrame._from_axes diff --git a/geopandas/geoseries.py b/geopandas/geoseries.py index ef85018..4256d82 100644 --- a/geopandas/geoseries.py +++ b/geopandas/geoseries.py @@ -753,8 +753,6 @@ class GeoSeries(GeoPandasBase, Series): def fillna(self, value=None, method=None, inplace=False, **kwargs): """Fill NA values with a geometry (empty polygon by default). - "method" is currently not implemented for pandas <= 0.12. - Examples -------- diff --git a/geopandas/io/tests/test_arrow.py b/geopandas/io/tests/test_arrow.py index ffe889a..8e87524 100644 --- a/geopandas/io/tests/test_arrow.py +++ b/geopandas/io/tests/test_arrow.py @@ -769,8 +769,6 @@ def test_read_versioned_file(version): df.to_feather(DATA_PATH / 'arrow' / f'test_data_v{METADATA_VERSION}.feather') # noqa: E501 df.to_parquet(DATA_PATH / 'arrow' / f'test_data_v{METADATA_VERSION}.parquet') # noqa: E501 """ - check_crs = Version(pyproj.__version__) >= Version("3.0.0") - expected = geopandas.GeoDataFrame( {"col_str": ["a", "b"], "col_int": [1, 2], "col_float": [0.1, 0.2]}, geometry=[MultiPolygon([box(0, 0, 1, 1), box(2, 2, 3, 3)]), box(4, 4, 5, 5)], @@ -778,10 +776,10 @@ def test_read_versioned_file(version): ) df = geopandas.read_feather(DATA_PATH / "arrow" / f"test_data_v{version}.feather") - assert_geodataframe_equal(df, expected, check_crs=check_crs) + assert_geodataframe_equal(df, expected, check_crs=True) df = geopandas.read_parquet(DATA_PATH / "arrow" / f"test_data_v{version}.parquet") - assert_geodataframe_equal(df, expected, check_crs=check_crs) + assert_geodataframe_equal(df, expected, check_crs=True) def test_read_gdal_files(): @@ -803,8 +801,6 @@ def test_read_gdal_files(): $ ogr2ogr -f Parquet -lco FID= test_data_gdal350.parquet test_data.gpkg $ ogr2ogr -f Arrow -lco FID= -lco GEOMETRY_ENCODING=WKB test_data_gdal350.arrow test_data.gpkg # noqa: E501 """ - check_crs = Version(pyproj.__version__) >= Version("3.0.0") - expected = geopandas.GeoDataFrame( {"col_str": ["a", "b"], "col_int": [1, 2], "col_float": [0.1, 0.2]}, geometry=[MultiPolygon([box(0, 0, 1, 1), box(2, 2, 3, 3)]), box(4, 4, 5, 5)], @@ -812,10 +808,10 @@ def test_read_gdal_files(): ) df = geopandas.read_parquet(DATA_PATH / "arrow" / "test_data_gdal350.parquet") - assert_geodataframe_equal(df, expected, check_crs=check_crs) + assert_geodataframe_equal(df, expected, check_crs=True) df = geopandas.read_feather(DATA_PATH / "arrow" / "test_data_gdal350.arrow") - assert_geodataframe_equal(df, expected, check_crs=check_crs) + assert_geodataframe_equal(df, expected, check_crs=True) def test_parquet_read_partitioned_dataset(tmpdir): diff --git a/geopandas/io/tests/test_file.py b/geopandas/io/tests/test_file.py index 416935d..bf2647d 100644 --- a/geopandas/io/tests/test_file.py +++ b/geopandas/io/tests/test_file.py @@ -1,15 +1,15 @@ -from collections import OrderedDict import datetime -from packaging.version import Version import io import os import pathlib import tempfile +from collections import OrderedDict import numpy as np import pandas as pd - +import pytest import pytz +from packaging.version import Version from pandas.api.types import is_datetime64_any_dtype from pandas.testing import assert_series_equal from shapely.geometry import Point, Polygon, box @@ -18,13 +18,9 @@ import geopandas from geopandas import GeoDataFrame, read_file from geopandas._compat import PANDAS_GE_20 from geopandas.io.file import _detect_driver, _EXTENSION_TO_DRIVER - from geopandas.testing import assert_geodataframe_equal, assert_geoseries_equal from geopandas.tests.util import PACKAGE_DIR, validate_boro_df -import pytest - - try: import pyogrio except ImportError: @@ -34,14 +30,11 @@ except ImportError: try: import fiona - # datetime roundtrip - FIONA_GE_1814 = Version(fiona.__version__) >= Version("1.8.14") # invalid datetime handling FIONA_GE_1821 = Version(fiona.__version__) >= Version("1.8.21") FIONA_GE_19 = Version(Version(fiona.__version__).base_version) >= Version("1.9.0") except ImportError: fiona = False - FIONA_GE_1814 = False FIONA_GE_1821 = False FIONA_GE_19 = False @@ -207,9 +200,6 @@ def test_to_file_datetime(tmpdir, driver, ext, time, engine): pytest.skip("pyogrio doesn't yet support timezones") if ext in (".shp", ""): pytest.skip(f"Driver corresponding to ext {ext} doesn't support dt fields") - if time.tzinfo is not None and FIONA_GE_1814 is False: - # https://github.com/Toblerity/Fiona/pull/915 - pytest.skip("Fiona >= 1.8.14 needed for timezone support") tempfilename = os.path.join(str(tmpdir), f"test_datetime{ext}") point = Point(0, 0) @@ -217,10 +207,7 @@ def test_to_file_datetime(tmpdir, driver, ext, time, engine): df = GeoDataFrame( {"a": [1.0, 2.0], "b": [time, time]}, geometry=[point, point], crs=4326 ) - if FIONA_GE_1814: - fiona_precision_limit = "ms" - else: - fiona_precision_limit = "s" + fiona_precision_limit = "ms" df["b"] = df["b"].dt.round(freq=fiona_precision_limit) df.to_file(tempfilename, driver=driver, engine=engine) @@ -307,7 +294,7 @@ def test_read_file_datetime_mixed_offsets(tmpdir): df.to_file(tempfilename) # check mixed tz don't crash GH2478 res = read_file(tempfilename) - if FIONA_GE_1814: + if engine == "fiona": # Convert mixed timezones to UTC equivalent assert is_datetime64_any_dtype(res["date"]) if not PANDAS_GE_20: diff --git a/geopandas/io/tests/test_pickle.py b/geopandas/io/tests/test_pickle.py index 5e3dbc0..131fbcf 100644 --- a/geopandas/io/tests/test_pickle.py +++ b/geopandas/io/tests/test_pickle.py @@ -3,15 +3,12 @@ See generate_legacy_storage_files.py for the creation of the legacy files. """ from contextlib import contextmanager -from packaging.version import Version import glob import os import pathlib import pandas as pd -import pyproj - import pytest from geopandas.testing import assert_geodataframe_equal from geopandas import _compat as compat @@ -48,13 +45,10 @@ def with_use_pygeos(option): @pytest.mark.skipif( - compat.USE_SHAPELY_20 - or compat.USE_PYGEOS - or (Version(pyproj.__version__) < Version("2.4")), + compat.USE_SHAPELY_20 or compat.USE_PYGEOS, reason=( "shapely 2.0/pygeos-based unpickling currently only works for " - "shapely-2.0/pygeos-written files; " - "old pyproj versions can't read pickles from newer pyproj versions" + "shapely-2.0/pygeos-written files" ), ) def test_legacy_pickles(current_pickle_data, legacy_pickle): diff --git a/geopandas/tests/test_array.py b/geopandas/tests/test_array.py index cbbde3e..f50ac26 100644 --- a/geopandas/tests/test_array.py +++ b/geopandas/tests/test_array.py @@ -941,15 +941,10 @@ class TestEstimateUtmCrs: self.landmarks = from_shapely([self.esb, self.sol], crs="epsg:4326") def test_estimate_utm_crs__geographic(self): - if compat.PYPROJ_LT_3: - with pytest.raises(RuntimeError, match=r"pyproj 3\+ required"): - self.landmarks.estimate_utm_crs() - else: - assert self.landmarks.estimate_utm_crs() == CRS("EPSG:32618") - if compat.PYPROJ_GE_32: # result is unstable in older pyproj - assert self.landmarks.estimate_utm_crs("NAD83") == CRS("EPSG:26918") + assert self.landmarks.estimate_utm_crs() == CRS("EPSG:32618") + if compat.PYPROJ_GE_32: # result is unstable in older pyproj + assert self.landmarks.estimate_utm_crs("NAD83") == CRS("EPSG:26918") - @pytest.mark.skipif(compat.PYPROJ_LT_3, reason="requires pyproj 3 or higher") def test_estimate_utm_crs__projected(self): assert self.landmarks.to_crs("EPSG:3857").estimate_utm_crs() == CRS( "EPSG:32618" @@ -966,14 +961,12 @@ class TestEstimateUtmCrs: ) assert antimeridian.estimate_utm_crs() == CRS("EPSG:32760") - @pytest.mark.skipif(compat.PYPROJ_LT_3, reason="requires pyproj 3 or higher") def test_estimate_utm_crs__out_of_bounds(self): with pytest.raises(RuntimeError, match="Unable to determine UTM CRS"): from_shapely( [shapely.geometry.Polygon([(0, 90), (1, 90), (2, 90)])], crs="EPSG:4326" ).estimate_utm_crs() - @pytest.mark.skipif(compat.PYPROJ_LT_3, reason="requires pyproj 3 or higher") def test_estimate_utm_crs__missing_crs(self): with pytest.raises(RuntimeError, match="crs must be set"): from_shapely( diff --git a/geopandas/tests/test_crs.py b/geopandas/tests/test_crs.py index b8983a6..20bd088 100644 --- a/geopandas/tests/test_crs.py +++ b/geopandas/tests/test_crs.py @@ -1,24 +1,14 @@ -from packaging.version import Version - import random import numpy as np import pandas as pd - -from shapely.geometry import Point, Polygon, LineString import pyproj +import pytest +from shapely.geometry import Point, Polygon, LineString from geopandas import GeoSeries, GeoDataFrame, points_from_xy, datasets, read_file from geopandas.array import from_shapely, from_wkb, from_wkt, GeometryArray - from geopandas.testing import assert_geodataframe_equal -import pytest - - -# pyproj 2.3.1 fixed a segfault for the case working in an environment with -# 'init' dicts (https://github.com/pyproj4/pyproj/issues/415) -PYPROJ_LT_231 = Version(pyproj.__version__) < Version("2.3.1") -PYPROJ_GE_3 = Version(pyproj.__version__) >= Version("3.0.0") def _create_df(x, y=None, crs=None): @@ -114,7 +104,6 @@ def test_to_crs_dimension_mixed(): "epsg:4326", pytest.param( {"init": "epsg:4326"}, - marks=pytest.mark.skipif(PYPROJ_LT_231, reason="segfault"), ), "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs", {"proj": "latlong", "ellps": "WGS84", "datum": "WGS84", "no_defs": True}, @@ -133,7 +122,6 @@ def epsg4326(request): "epsg:26918", pytest.param( {"init": "epsg:26918", "no_defs": True}, - marks=pytest.mark.skipif(PYPROJ_LT_231, reason="segfault"), ), "+proj=utm +zone=18 +ellps=GRS80 +datum=NAD83 +units=m +no_defs ", {"proj": "utm", "zone": 18, "datum": "NAD83", "units": "m", "no_defs": True}, @@ -152,8 +140,7 @@ def test_transform2(epsg4326, epsg26918): # with PROJ >= 7, the transformation using EPSG code vs proj4 string is # slightly different due to use of grid files or not -> turn off network # to not use grid files at all for this test - if PYPROJ_GE_3: - pyproj.network.set_network_enabled(False) + pyproj.network.set_network_enabled(False) df = df_epsg26918() lonlat = df.to_crs(**epsg4326) diff --git a/geopandas/tests/test_dissolve.py b/geopandas/tests/test_dissolve.py index 6d9b740..8192a0c 100644 --- a/geopandas/tests/test_dissolve.py +++ b/geopandas/tests/test_dissolve.py @@ -5,7 +5,6 @@ import pandas as pd import geopandas from geopandas import GeoDataFrame, read_file -from geopandas import _compat as compat from pandas.testing import assert_frame_equal import pytest @@ -296,9 +295,6 @@ def test_dissolve_categorical(): ) -@pytest.mark.skipif( - not compat.PANDAS_GE_11, reason="dropna groupby kwarg added in pandas 1.1.0" -) def test_dissolve_dropna(): gdf = geopandas.GeoDataFrame( { @@ -328,9 +324,6 @@ def test_dissolve_dropna(): assert_frame_equal(expected_no_na, gdf.dissolve("a")) -@pytest.mark.skipif( - compat.PANDAS_GE_11, reason="dropna warning is only emitted if pandas < 1.1.0" -) def test_dissolve_dropna_warn(nybb_polydf): # No warning with default params with warnings.catch_warnings(record=True) as record: @@ -339,12 +332,6 @@ def test_dissolve_dropna_warn(nybb_polydf): for r in record: assert "dropna kwarg is not supported" not in str(r.message) - # Warning is emitted with non-default dropna value - with pytest.warns( - UserWarning, match="dropna kwarg is not supported for pandas < 1.1.0" - ): - nybb_polydf.dissolve(dropna=False) - def test_dissolve_multi_agg(nybb_polydf, merged_shapes): diff --git a/geopandas/tests/test_geodataframe.py b/geopandas/tests/test_geodataframe.py index 878403d..6efbbd2 100644 --- a/geopandas/tests/test_geodataframe.py +++ b/geopandas/tests/test_geodataframe.py @@ -884,13 +884,9 @@ class TestDataFrame: assert self.df.crs == unpickled.crs def test_estimate_utm_crs(self): - if compat.PYPROJ_LT_3: - with pytest.raises(RuntimeError, match=r"pyproj 3\+ required"): - self.df.estimate_utm_crs() - else: - assert self.df.estimate_utm_crs() == CRS("EPSG:32618") - if compat.PYPROJ_GE_32: # result is unstable in older pyproj - assert self.df.estimate_utm_crs("NAD83") == CRS("EPSG:26918") + assert self.df.estimate_utm_crs() == CRS("EPSG:32618") + if compat.PYPROJ_GE_32: # result is unstable in older pyproj + assert self.df.estimate_utm_crs("NAD83") == CRS("EPSG:26918") def test_to_wkb(self): wkbs0 = [ diff --git a/geopandas/tests/test_geom_methods.py b/geopandas/tests/test_geom_methods.py index eccd5c0..7a09352 100644 --- a/geopandas/tests/test_geom_methods.py +++ b/geopandas/tests/test_geom_methods.py @@ -1051,10 +1051,6 @@ class TestGeomMethods: exploded_df = gdf.explode(column="col1") assert_geodataframe_equal(exploded_df, expected_df) - @pytest.mark.skipif( - not compat.PANDAS_GE_11, - reason="ignore_index keyword introduced in pandas 1.1.0", - ) def test_explode_pandas_fallback_ignore_index(self): d = { "col1": [["name1", "name2"], ["name3", "name4"]], diff --git a/geopandas/tests/test_geoseries.py b/geopandas/tests/test_geoseries.py index d4b1425..5dc8015 100644 --- a/geopandas/tests/test_geoseries.py +++ b/geopandas/tests/test_geoseries.py @@ -209,28 +209,21 @@ class TestSeries: self.landmarks.to_crs(crs=None, epsg=None) def test_estimate_utm_crs__geographic(self): - if compat.PYPROJ_LT_3: - with pytest.raises(RuntimeError, match=r"pyproj 3\+ required"): - self.landmarks.estimate_utm_crs() - else: - assert self.landmarks.estimate_utm_crs() == CRS("EPSG:32618") - if compat.PYPROJ_GE_32: # result is unstable in older pyproj - assert self.landmarks.estimate_utm_crs("NAD83") == CRS("EPSG:26918") + assert self.landmarks.estimate_utm_crs() == CRS("EPSG:32618") + if compat.PYPROJ_GE_32: # result is unstable in older pyproj + assert self.landmarks.estimate_utm_crs("NAD83") == CRS("EPSG:26918") - @pytest.mark.skipif(compat.PYPROJ_LT_3, reason="requires pyproj 3 or higher") def test_estimate_utm_crs__projected(self): assert self.landmarks.to_crs("EPSG:3857").estimate_utm_crs() == CRS( "EPSG:32618" ) - @pytest.mark.skipif(compat.PYPROJ_LT_3, reason="requires pyproj 3 or higher") def test_estimate_utm_crs__out_of_bounds(self): with pytest.raises(RuntimeError, match="Unable to determine UTM CRS"): GeoSeries( [Polygon([(0, 90), (1, 90), (2, 90)])], crs="EPSG:4326" ).estimate_utm_crs() - @pytest.mark.skipif(compat.PYPROJ_LT_3, reason="requires pyproj 3 or higher") def test_estimate_utm_crs__missing_crs(self): with pytest.raises(RuntimeError, match="crs must be set"): GeoSeries([Polygon([(0, 90), (1, 90), (2, 90)])]).estimate_utm_crs() diff --git a/geopandas/tests/test_merge.py b/geopandas/tests/test_merge.py index f048b9a..034f272 100644 --- a/geopandas/tests/test_merge.py +++ b/geopandas/tests/test_merge.py @@ -8,7 +8,6 @@ from pandas.testing import assert_index_equal from shapely.geometry import Point from geopandas import GeoDataFrame, GeoSeries -from geopandas import _compat as compat class TestMerging: @@ -172,11 +171,6 @@ class TestMerging: # check metadata comes from first df self._check_metadata(res3, geometry_column_name="geom", crs="epsg:4326") - @pytest.mark.xfail( - not compat.PANDAS_GE_11, - reason="pandas <=1.0 hard codes concat([GeoSeries, GeoSeries]) -> " - "DataFrame or Union[DataFrame, SparseDataFrame] in 0.25", - ) @pytest.mark.filterwarnings("ignore:Accessing CRS") def test_concat_axis1_geoseries(self): gseries2 = GeoSeries([Point(i, i) for i in range(3, 6)], crs="epsg:4326") diff --git a/geopandas/tests/test_op_output_types.py b/geopandas/tests/test_op_output_types.py index 789982b..52d048f 100644 --- a/geopandas/tests/test_op_output_types.py +++ b/geopandas/tests/test_op_output_types.py @@ -227,9 +227,7 @@ def test_apply(df): assert_object(df[["value1"]].apply(identity, axis=1), pd.DataFrame) -@pytest.mark.xfail(not compat.PANDAS_GE_11, reason="apply is different in pandas 1.0.5") def test_apply_axis1_secondary_geo_cols(df): - # note #GH2436 would also fix this def identity(x): return x @@ -243,10 +241,6 @@ def test_expanddim_in_apply(): assert_object(result, pd.DataFrame) -@pytest.mark.xfail( - not compat.PANDAS_GE_11, - reason="pandas <1.1 don't preserve subclass through groupby ops", # Pandas GH33884 -) def test_expandim_in_groupby_aggregate_multiple_funcs(): # https://github.com/geopandas/geopandas/pull/2296#issuecomment-1021966443 # There are two calls to _constructor_expanddim here @@ -270,10 +264,6 @@ def test_expandim_in_groupby_aggregate_multiple_funcs(): assert_object(grouped.agg([total_area]), pd.DataFrame) -@pytest.mark.xfail( - not compat.PANDAS_GE_11, - reason="pandas <1.1 uses concat([Series]) in unstack", # Pandas GH33356 -) def test_expanddim_in_unstack(): # https://github.com/geopandas/geopandas/pull/2296#issuecomment-1021966443 s = GeoSeries.from_xy( diff --git a/geopandas/tests/test_overlay.py b/geopandas/tests/test_overlay.py index e92f04c..026c055 100644 --- a/geopandas/tests/test_overlay.py +++ b/geopandas/tests/test_overlay.py @@ -8,7 +8,6 @@ from shapely.geometry import Point, Polygon, LineString, GeometryCollection, box import geopandas from geopandas import GeoDataFrame, GeoSeries, overlay, read_file -from geopandas import _compat from geopandas._compat import PANDAS_GE_20 from geopandas.testing import assert_geodataframe_equal, assert_geoseries_equal @@ -199,10 +198,7 @@ def test_overlay_nybb(how): # first, check that all bounds and areas are approx equal # this is a very rough check for multipolygon equality - if not _compat.PANDAS_GE_11: - kwargs = dict(check_less_precise=True) - else: - kwargs = {} + kwargs = {} pd.testing.assert_series_equal( result.geometry.area, expected.geometry.area, **kwargs ) diff --git a/geopandas/tests/test_pandas_methods.py b/geopandas/tests/test_pandas_methods.py index 3875ada..10cae2e 100644 --- a/geopandas/tests/test_pandas_methods.py +++ b/geopandas/tests/test_pandas_methods.py @@ -550,18 +550,12 @@ def test_groupby(df): # applying on the geometry column res = df.groupby("value2")["geometry"].apply(lambda x: x.unary_union) - if compat.PANDAS_GE_11: - exp = GeoSeries( - [shapely.geometry.MultiPoint([(0, 0), (2, 2)]), Point(1, 1)], - index=pd.Index([1, 2], name="value2"), - name="geometry", - ) - else: - exp = pd.Series( - [shapely.geometry.MultiPoint([(0, 0), (2, 2)]), Point(1, 1)], - index=pd.Index([1, 2], name="value2"), - name="geometry", - ) + + exp = GeoSeries( + [shapely.geometry.MultiPoint([(0, 0), (2, 2)]), Point(1, 1)], + index=pd.Index([1, 2], name="value2"), + name="geometry", + ) assert_series_equal(res, exp) # apply on geometry column not resulting in new geometry diff --git a/geopandas/tests/test_plotting.py b/geopandas/tests/test_plotting.py index 2a4041e..52925c9 100644 --- a/geopandas/tests/test_plotting.py +++ b/geopandas/tests/test_plotting.py @@ -1,4 +1,3 @@ -from packaging.version import Version import itertools import warnings @@ -34,11 +33,7 @@ import matplotlib.pyplot as plt # noqa try: # skipif and importorskip do not work for decorators from matplotlib.testing.decorators import check_figures_equal - if Version(matplotlib.__version__) >= Version("3.3.0"): - - MPL_DECORATORS = True - else: - MPL_DECORATORS = False + MPL_DECORATORS = True except ImportError: MPL_DECORATORS = False @@ -988,7 +983,7 @@ class TestGeometryCollectionPlotting: class TestNonuniformGeometryPlotting: def setup_method(self): - pytest.importorskip("matplotlib", "1.5.0") + pytest.importorskip("matplotlib") poly = Polygon([(1, 0), (2, 0), (2, 1)]) line = LineString([(0.5, 0.5), (1, 1), (1, 0.5), (1.5, 1)]) diff --git a/geopandas/tests/test_sindex.py b/geopandas/tests/test_sindex.py index 91a7165..eca7242 100644 --- a/geopandas/tests/test_sindex.py +++ b/geopandas/tests/test_sindex.py @@ -166,9 +166,6 @@ class TestFrameSindex: geometry_col = self.df.geometry assert geometry_col.sindex is original_index - @pytest.mark.skipif( - not compat.PANDAS_GE_11, reason="Column selection returns a copy on pd<=1.1.0" - ) def test_rebuild_on_multiple_col_selection(self): """Selecting a subset of columns preserves the index.""" original_index = self.df.sindex @@ -192,7 +189,6 @@ class TestFrameSindex: # sorting should still have happened though assert gdf.index.tolist() == [4, 3, 2, 1, 0] - @pytest.mark.skipif(not compat.PANDAS_GE_11, reason="fails on pd<1.1.0") def test_update_inplace_no_rebuild(self): gdf = self.df.copy() old_sindex = gdf.sindex diff --git a/geopandas/tools/tests/test_sjoin.py b/geopandas/tools/tests/test_sjoin.py index c8e320e..8299f6b 100644 --- a/geopandas/tools/tests/test_sjoin.py +++ b/geopandas/tools/tests/test_sjoin.py @@ -1,4 +1,3 @@ -from packaging.version import Version import math from typing import Sequence from geopandas.testing import assert_geodataframe_equal @@ -364,9 +363,7 @@ class TestSpatialJoin: columns={"df1_ix1": "index_left0", "df1_ix2": "index_left1"} ) exp.index.names = df2.index.names - - # GH 1364 fix of behaviour was done in pandas 1.1.0 - if predicate == "within" and Version(pd.__version__) >= Version("1.1.0"): + if predicate == "within": exp = exp.sort_index() assert_frame_equal(res, exp, check_index_type=False) diff --git a/pyproject.toml b/pyproject.toml index ff61288..84be25f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,11 +27,11 @@ classifiers = [ ] requires-python = ">=3.8" dependencies = [ - "fiona >= 1.8", + "fiona >= 1.8.19", "packaging", - "pandas >= 1.0.0", - "pyproj >= 2.6.1.post1", - "shapely >= 1.7", + "pandas >= 1.1.0", + "pyproj >= 3.0.1", + "shapely >= 1.7.1", ] [project.readme] diff --git a/requirements-dev.txt b/requirements-dev.txt index dac7d96..1acf6cb 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,8 +1,8 @@ # required -fiona>=1.8 -pandas>=1.0.0 -pyproj>=2.6.1.post1 -shapely>=1.7 +fiona>=1.8.19 +pandas>=1.1.0 +pyproj>=3.0.1 +shapely>=1.7.1 packaging # geodatabase access @@ -13,7 +13,7 @@ SQLAlchemy>=1.3 geopy # plotting -matplotlib>=3.2 +matplotlib>=3.3.4 mapclassify # testing