[Git][debian-gis-team/python-geopandas][upstream] New upstream version 0.11.1
Bas Couwenberg (@sebastic)
gitlab at salsa.debian.org
Sun Jul 24 16:41:11 BST 2022
Bas Couwenberg pushed to branch upstream at Debian GIS Project / python-geopandas
Commits:
1535f78f by Bas Couwenberg at 2022-07-24T17:25:18+02:00
New upstream version 0.11.1
- - - - -
15 changed files:
- CHANGELOG.md
- CONTRIBUTING.md
- doc/source/community/contributing.rst
- doc/source/docs/user_guide/aggregation_with_dissolve.rst
- geopandas/_version.py
- geopandas/geodataframe.py
- geopandas/io/arrow.py
- geopandas/io/file.py
- geopandas/io/tests/test_arrow.py
- geopandas/io/tests/test_file.py
- geopandas/tests/test_geodataframe.py
- geopandas/tests/test_geom_methods.py
- geopandas/tests/test_op_output_types.py
- geopandas/tests/test_pandas_methods.py
- geopandas/tools/_show_versions.py
Changes:
=====================================
CHANGELOG.md
=====================================
@@ -1,6 +1,41 @@
Changelog
=========
+Development version
+-------------------
+
+New features and improvements:
+
+Deprecations and compatibility notes:
+
+Bug fixes:
+
+Notes on (optional) dependencies:
+
+Version 0.11.1 (July 24, 2022)
+------------------------------
+
+Small bug-fix release:
+
+- Fix regression (RecursionError) in reshape methods such as ``unstack()``
+ and ``pivot()`` involving MultiIndex, or GeoDataFrame construction with
+ MultiIndex (#2486).
+- Fix regression in ``GeoDataFrame.explode()`` with non-default
+ geometry column name.
+- Fix regression in ``apply()`` causing row-wise all nan float columns to be
+ casted to GeometryDtype (#2482).
+- Fix a crash in datetime column reading where the file contains mixed timezone
+ offsets (#2479). These will be read as UTC localized values.
+- Fix a crash in datetime column reading where the file contains datetimes
+ outside the range supported by [ns] precision (#2505).
+- Fix regression in passing the Parquet or Feather format ``version`` in
+ ``to_parquet`` and ``to_feather``. As a result, the ``version`` parameter
+ for the ``to_parquet`` and ``to_feather`` methods has been replaced with
+ ``schema_version``. ``version`` will be passed directly to underlying
+ feather or parquet writer. ``version`` will only be used to set
+ ``schema_version`` if ``version`` is one of 0.1.0 or 0.4.0 (#2496).
+
+
Version 0.11 (June 20, 2022)
----------------------------
@@ -121,7 +156,6 @@ Notes on (optional) dependencies:
dependencies have now changed to shapely 1.7, fiona 1.8.13.post1, pyproj 2.6.1.post1,
matplotlib 3.2, mapclassify 2.4.0 (#2358, #2391)
-
Version 0.10.2 (October 16, 2021)
---------------------------------
@@ -141,7 +175,6 @@ Small bug-fix release:
- Fix ``unary_union`` to correctly handle a GeoSeries with missing values (#2181).
- Avoid internal deprecation warning in ``clip()`` (#2179).
-
Version 0.10.1 (October 8, 2021)
--------------------------------
@@ -150,7 +183,6 @@ Small bug-fix release:
- Fix regression in ``overlay()`` with non-overlapping geometries and a
non-default ``how`` (i.e. not "intersection") (#2157).
-
Version 0.10.0 (October 3, 2021)
--------------------------------
@@ -187,7 +219,7 @@ New features and improvements:
- Improved heuristic to decide how many decimals to show in the repr based on
whether the CRS is projected or geographic (#1895).
- Switched the default for ``geocode()`` from GeoCode.Farm to the Photon
- geocoding API (https://photon.komoot.io) (#2007).
+ geocoding API (<https://photon.komoot.io>) (#2007).
Deprecations and compatibility notes:
@@ -237,7 +269,6 @@ Notes on (optional) dependencies:
- Compatibility fixes for the latest PyGEOS (#1872, #2014) and matplotlib
(colorbar issue, #2066).
-
Version 0.9.0 (February 28, 2021)
---------------------------------
@@ -354,13 +385,11 @@ Notes on (optional) dependencies:
is still a default requirement) (#1775).
- Compatibility with the upcoming Shapely 1.8 (#1659, #1662, #1819).
-
Version 0.8.2 (January 25, 2021)
--------------------------------
Small bug-fix release for compatibility with PyGEOS 0.9.
-
Version 0.8.1 (July 15, 2020)
-----------------------------
@@ -372,7 +401,6 @@ Small bug-fix release:
- Fix the un-pickling with ``pd.read_pickle`` of files written with older
GeoPandas versions (#1511).
-
Version 0.8.0 (June 24, 2020)
-----------------------------
@@ -471,7 +499,6 @@ And we now have a [Code of Conduct](https://github.com/geopandas/geopandas/blob/
GeoPandas 0.8.0 is the last release to support Python 3.5. The next release
will require Python 3.6, pandas 0.24, numpy 1.15 and shapely 1.6 or higher.
-
Version 0.7.0 (February 16, 2020)
---------------------------------
@@ -516,7 +543,6 @@ Bug fixes:
- Fixed the ``geopandas.sjoin`` function to handle MultiIndex correctly (#1159).
- Fixed the ``geopandas.sjoin`` function to preserve the index name of the left GeoDataFrame (#1150).
-
Version 0.6.3 (February 6, 2020)
---------------------------------
@@ -527,7 +553,6 @@ Small bug-fix release:
no missing values in the geometry column. This should make it easier to fill
the numerical columns of the GeoDataFrame (#1279).
-
Version 0.6.2 (November 18, 2019)
---------------------------------
@@ -540,7 +565,6 @@ Small bug-fix release fixing a few regressions:
- Fix filtering of a GeoDataFrame to preserve the index type when ending up
with an empty result (#1190).
-
Version 0.6.1 (October 12, 2019)
--------------------------------
@@ -549,7 +573,6 @@ Small bug-fix release fixing a few regressions:
- Fix ``astype`` when converting to string with Multi geometries (#1145) or when converting a dataframe without geometries (#1144).
- Fix ``GeoSeries.fillna`` to accept ``np.nan`` again (#1149).
-
Version 0.6.0 (September 27, 2019)
----------------------------------
@@ -590,10 +613,8 @@ Bug fixes:
- Fixed ``GeoDataFrame.to_file`` to preserve VFS file paths (e.g. when a "s3://" path is specified) (#1124).
- Fixed failing case in ``geopandas.sjoin`` with empty geometries (#1138).
-
In addition, the minimum required versions of some dependencies have been increased: GeoPandas now requirs pandas >=0.23.4 and matplotlib >=2.0.1 (#1002).
-
Version 0.5.1 (July 11, 2019)
-----------------------------
=====================================
CONTRIBUTING.md
=====================================
@@ -32,6 +32,9 @@ In particular, when submitting a pull request:
line of a docstring should be a standalone summary. Parameters and
return values should be documented explicitly.
+- Unless your PR implements minor changes or internal work only, make sure
+ it contains a note describing the changes in the `CHANGELOG.md` file.
+
Improving the documentation and testing for code already in GeoPandas
is a great way to get started if you'd like to make a contribution.
=====================================
doc/source/community/contributing.rst
=====================================
@@ -47,6 +47,9 @@ In particular, when submitting a pull request:
- GeoPandas supports Python 3.8+ only. The last version of GeoPandas
supporting Python 2 is 0.6.
+- Unless your PR implements minor changes or internal work only, make sure
+ it contains a note describing the changes in the `CHANGELOG.md` file.
+
Seven Steps for Contributing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
=====================================
doc/source/docs/user_guide/aggregation_with_dissolve.rst
=====================================
@@ -80,7 +80,7 @@ However it also accepts other summary statistic options as allowed by :meth:`pan
* list of functions and/or function names, e.g. [np.sum, 'mean']
* dict of axis labels -> functions, function names or list of such.
-For example, to get the number of contries on each continent,
+For example, to get the number of countries on each continent,
as well as the populations of the largest and smallest country of each,
we can aggregate the ``'name'`` column using ``'count'``,
and the ``'pop_est'`` column using ``'min'`` and ``'max'``:
@@ -96,4 +96,4 @@ and the ``'pop_est'`` column using ``'min'`` and ``'max'``:
},
)
- continents.head()
\ No newline at end of file
+ continents.head()
=====================================
geopandas/_version.py
=====================================
@@ -23,9 +23,9 @@ def get_keywords():
# setup.py/versioneer.py will grep for the variable names, so they must
# each be defined on a line of their own. _version.py will just call
# get_keywords().
- git_refnames = " (HEAD -> main, tag: v0.11.0)"
- git_full = "1977b5036b9ca3a034e65ea1f5ba48b7225550a7"
- git_date = "2022-06-21 08:00:39 +0200"
+ git_refnames = " (HEAD -> main, tag: v0.11.1)"
+ git_full = "1f7160050b31e0f39410c7f4163a2cbb2648ff62"
+ git_date = "2022-07-24 13:17:38 +0200"
keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
return keywords
=====================================
geopandas/geodataframe.py
=====================================
@@ -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
@@ -996,7 +1000,7 @@ individually so that features may have different properties
return df
def to_parquet(
- self, path, index=None, compression="snappy", version=None, **kwargs
+ self, path, index=None, compression="snappy", schema_version=None, **kwargs
):
"""Write a GeoDataFrame to the Parquet format.
@@ -1026,7 +1030,7 @@ individually so that features may have different properties
output except `RangeIndex` which is stored as metadata only.
compression : {'snappy', 'gzip', 'brotli', None}, default 'snappy'
Name of the compression to use. Use ``None`` for no compression.
- version : {'0.1.0', '0.4.0', None}
+ schema_version : {'0.1.0', '0.4.0', None}
GeoParquet specification version; if not provided will default to
latest supported version.
kwargs
@@ -1056,10 +1060,17 @@ individually so that features may have different properties
from geopandas.io.arrow import _to_parquet
_to_parquet(
- self, path, compression=compression, index=index, version=version, **kwargs
+ self,
+ path,
+ compression=compression,
+ index=index,
+ schema_version=schema_version,
+ **kwargs,
)
- def to_feather(self, path, index=None, compression=None, version=None, **kwargs):
+ def to_feather(
+ self, path, index=None, compression=None, schema_version=None, **kwargs
+ ):
"""Write a GeoDataFrame to the Feather format.
Any geometry columns present are serialized to WKB format in the file.
@@ -1089,7 +1100,7 @@ individually so that features may have different properties
compression : {'zstd', 'lz4', 'uncompressed'}, optional
Name of the compression to use. Use ``"uncompressed"`` for no
compression. By default uses LZ4 if available, otherwise uncompressed.
- version : {'0.1.0', '0.4.0', None}
+ schema_version : {'0.1.0', '0.4.0', None}
GeoParquet specification version; if not provided will default to
latest supported version.
kwargs
@@ -1110,7 +1121,12 @@ individually so that features may have different properties
from geopandas.io.arrow import _to_feather
_to_feather(
- self, path, index=index, compression=compression, version=version, **kwargs
+ self,
+ path,
+ index=index,
+ compression=compression,
+ schema_version=schema_version,
+ **kwargs,
)
def to_file(self, filename, driver=None, schema=None, index=None, **kwargs):
@@ -1508,14 +1524,17 @@ individually so that features may have different properties
else:
if self.crs is not None and result.crs is None:
result.set_crs(self.crs, inplace=True)
- elif isinstance(result, Series):
- # Reconstruct series GeometryDtype if lost by apply
- try:
- # Note CRS cannot be preserved in this case as func could refer
- # to any column
- result = _ensure_geometry(result)
- except TypeError:
- pass
+ elif isinstance(result, Series) and result.dtype == "object":
+ # Try reconstruct series GeometryDtype if lost by apply
+ # If all none and object dtype assert list of nones is more likely
+ # intended than list of null geometry.
+ if not result.isna().all():
+ try:
+ # not enough info about func to preserve CRS
+ result = _ensure_geometry(result)
+
+ except TypeError:
+ pass
return result
@@ -1809,12 +1828,11 @@ individually so that features may have different properties
exploded_geom = self.geometry.reset_index(drop=True).explode(index_parts=True)
- df = GeoDataFrame(
- self.drop(self._geometry_column_name, axis=1).take(
- exploded_geom.index.droplevel(-1)
- ),
- geometry=exploded_geom.values,
- ).__finalize__(self)
+ df = self.drop(self._geometry_column_name, axis=1).take(
+ exploded_geom.index.droplevel(-1)
+ )
+ df[exploded_geom.name] = exploded_geom.values
+ df = df.set_geometry(self._geometry_column_name).__finalize__(self)
if ignore_index:
df.reset_index(inplace=True, drop=True)
=====================================
geopandas/io/arrow.py
=====================================
@@ -66,13 +66,13 @@ def _remove_id_from_member_of_ensembles(json_dict):
member.pop("id", None)
-def _create_metadata(df, version=None):
+def _create_metadata(df, schema_version=None):
"""Create and encode geo metadata dict.
Parameters
----------
df : GeoDataFrame
- version : {'0.1.0', '0.4.0', None}
+ schema_version : {'0.1.0', '0.4.0', None}
GeoParquet specification version; if not provided will default to
latest supported version.
@@ -81,10 +81,12 @@ def _create_metadata(df, version=None):
dict
"""
- version = version or METADATA_VERSION
+ schema_version = schema_version or METADATA_VERSION
- if version not in SUPPORTED_VERSIONS:
- raise ValueError(f"version must be one of: {', '.join(SUPPORTED_VERSIONS)}")
+ if schema_version not in SUPPORTED_VERSIONS:
+ raise ValueError(
+ f"schema_version must be one of: {', '.join(SUPPORTED_VERSIONS)}"
+ )
# Construct metadata for each geometry
column_metadata = {}
@@ -94,7 +96,7 @@ def _create_metadata(df, version=None):
crs = None
if series.crs:
- if version == "0.1.0":
+ if schema_version == "0.1.0":
crs = series.crs.to_wkt()
else: # version >= 0.4.0
crs = series.crs.to_json_dict()
@@ -112,7 +114,7 @@ def _create_metadata(df, version=None):
return {
"primary_column": df._geometry_column_name,
"columns": column_metadata,
- "version": METADATA_VERSION,
+ "version": schema_version or METADATA_VERSION,
"creator": {"library": "geopandas", "version": geopandas.__version__},
}
@@ -224,7 +226,7 @@ def _validate_metadata(metadata):
raise ValueError("Only WKB geometry encoding is supported")
-def _geopandas_to_arrow(df, index=None, version=None):
+def _geopandas_to_arrow(df, index=None, schema_version=None):
"""
Helper function with main, shared logic for to_parquet/to_feather.
"""
@@ -233,7 +235,7 @@ def _geopandas_to_arrow(df, index=None, version=None):
_validate_dataframe(df)
# create geo metadata before altering incoming data frame
- geo_metadata = _create_metadata(df, version=version)
+ geo_metadata = _create_metadata(df, schema_version=schema_version)
df = df.to_wkb()
@@ -243,10 +245,13 @@ def _geopandas_to_arrow(df, index=None, version=None):
# This must be done AFTER creating the table or it is not persisted
metadata = table.schema.metadata
metadata.update({b"geo": _encode_metadata(geo_metadata)})
+
return table.replace_schema_metadata(metadata)
-def _to_parquet(df, path, index=None, compression="snappy", version=None, **kwargs):
+def _to_parquet(
+ df, path, index=None, compression="snappy", schema_version=None, **kwargs
+):
"""
Write a GeoDataFrame to the Parquet format.
@@ -270,7 +275,7 @@ def _to_parquet(df, path, index=None, compression="snappy", version=None, **kwar
output except `RangeIndex` which is stored as metadata only.
compression : {'snappy', 'gzip', 'brotli', None}, default 'snappy'
Name of the compression to use. Use ``None`` for no compression.
- version : {'0.1.0', '0.4.0', None}
+ schema_version : {'0.1.0', '0.4.0', None}
GeoParquet specification version; if not provided will default to
latest supported version.
kwargs
@@ -280,12 +285,23 @@ def _to_parquet(df, path, index=None, compression="snappy", version=None, **kwar
"pyarrow.parquet", extra="pyarrow is required for Parquet support."
)
+ if kwargs and "version" in kwargs and kwargs["version"] is not None:
+ if schema_version is None and kwargs["version"] in SUPPORTED_VERSIONS:
+ warnings.warn(
+ "the `version` parameter has been replaced with `schema_version`. "
+ "`version` will instead be passed directly to the underlying "
+ "parquet writer unless `version` is 0.1.0 or 0.4.0.",
+ FutureWarning,
+ stacklevel=2,
+ )
+ schema_version = kwargs.pop("version")
+
path = _expand_user(path)
- table = _geopandas_to_arrow(df, index=index, version=version)
+ table = _geopandas_to_arrow(df, index=index, schema_version=schema_version)
parquet.write_table(table, path, compression=compression, **kwargs)
-def _to_feather(df, path, index=None, compression=None, version=None, **kwargs):
+def _to_feather(df, path, index=None, compression=None, schema_version=None, **kwargs):
"""
Write a GeoDataFrame to the Feather format.
@@ -310,7 +326,7 @@ def _to_feather(df, path, index=None, compression=None, version=None, **kwargs):
compression : {'zstd', 'lz4', 'uncompressed'}, optional
Name of the compression to use. Use ``"uncompressed"`` for no
compression. By default uses LZ4 if available, otherwise uncompressed.
- version : {'0.1.0', '0.4.0', None}
+ schema_version : {'0.1.0', '0.4.0', None}
GeoParquet specification version; if not provided will default to
latest supported version.
kwargs
@@ -325,8 +341,19 @@ def _to_feather(df, path, index=None, compression=None, version=None, **kwargs):
if Version(pyarrow.__version__) < Version("0.17.0"):
raise ImportError("pyarrow >= 0.17 required for Feather support")
+ if kwargs and "version" in kwargs and kwargs["version"] is not None:
+ if schema_version is None and kwargs["version"] in SUPPORTED_VERSIONS:
+ warnings.warn(
+ "the `version` parameter has been replaced with `schema_version`. "
+ "`version` will instead be passed directly to the underlying "
+ "feather writer unless `version` is 0.1.0 or 0.4.0.",
+ FutureWarning,
+ stacklevel=2,
+ )
+ schema_version = kwargs.pop("version")
+
path = _expand_user(path)
- table = _geopandas_to_arrow(df, index=index, version=version)
+ table = _geopandas_to_arrow(df, index=index, schema_version=schema_version)
feather.write_feather(table, path, compression=compression, **kwargs)
@@ -337,6 +364,7 @@ def _arrow_to_geopandas(table, metadata=None):
df = table.to_pandas()
metadata = metadata or table.schema.metadata
+
if metadata is None or b"geo" not in metadata:
raise ValueError(
"""Missing geo metadata in Parquet/Feather file.
=====================================
geopandas/io/file.py
=====================================
@@ -341,9 +341,16 @@ def _read_file_fiona(
f_filt, crs=crs, columns=columns + ["geometry"]
)
for k in datetime_fields:
- # fiona only supports up to ms precision, any microseconds are
- # floating point rounding error
- df[k] = pd.to_datetime(df[k]).dt.round(freq="ms")
+ as_dt = pd.to_datetime(df[k], errors="ignore")
+ # if to_datetime failed, try again for mixed timezone offsets
+ if as_dt.dtype == "object":
+ # This can still fail if there are invalid datetimes
+ as_dt = pd.to_datetime(df[k], errors="ignore", utc=True)
+ # if to_datetime succeeded, round datetimes as
+ # fiona only supports up to ms precision (any microseconds are
+ # floating point rounding error)
+ if not (as_dt.dtype == "object"):
+ df[k] = as_dt.dt.round(freq="ms")
return df
=====================================
geopandas/io/tests/test_arrow.py
=====================================
@@ -105,8 +105,8 @@ def test_crs_metadata_datum_ensemble():
def test_write_metadata_invalid_spec_version():
gdf = geopandas.GeoDataFrame(geometry=[box(0, 0, 10, 10)], crs="EPSG:4326")
- with pytest.raises(ValueError, match="version must be one of"):
- _create_metadata(gdf, version="invalid")
+ with pytest.raises(ValueError, match="schema_version must be one of"):
+ _create_metadata(gdf, schema_version="invalid")
def test_encode_metadata():
@@ -259,7 +259,7 @@ def test_to_parquet_does_not_pass_engine_along(mock_to_parquet):
# assert that engine keyword is not passed through to _to_parquet (and thus
# parquet.write_table)
mock_to_parquet.assert_called_with(
- df, "", compression="snappy", index=None, version=None
+ df, "", compression="snappy", index=None, schema_version=None
)
@@ -679,9 +679,10 @@ def test_write_read_default_crs(tmpdir, format):
@pytest.mark.parametrize(
- "format,version", product(["feather", "parquet"], [None] + SUPPORTED_VERSIONS)
+ "format,schema_version",
+ product(["feather", "parquet"], [None] + SUPPORTED_VERSIONS),
)
-def test_write_spec_version(tmpdir, format, version):
+def test_write_spec_version(tmpdir, format, schema_version):
if format == "feather":
from pyarrow.feather import read_table
@@ -691,7 +692,7 @@ def test_write_spec_version(tmpdir, format, version):
filename = os.path.join(str(tmpdir), f"test.{format}")
gdf = geopandas.GeoDataFrame(geometry=[box(0, 0, 10, 10)], crs="EPSG:4326")
write = getattr(gdf, f"to_{format}")
- write(filename, version=version)
+ write(filename, schema_version=schema_version)
# ensure that we can roundtrip data regardless of version
read = getattr(geopandas, f"read_{format}")
@@ -700,10 +701,10 @@ def test_write_spec_version(tmpdir, format, version):
table = read_table(filename)
metadata = json.loads(table.schema.metadata[b"geo"])
- assert metadata["version"] == version or METADATA_VERSION
+ assert metadata["version"] == schema_version or METADATA_VERSION
# verify that CRS is correctly handled between versions
- if version == "0.1.0":
+ if schema_version == "0.1.0":
assert metadata["columns"]["geometry"]["crs"] == gdf.crs.to_wkt()
else:
@@ -712,6 +713,46 @@ def test_write_spec_version(tmpdir, format, version):
assert metadata["columns"]["geometry"]["crs"] == crs_expected
+ at pytest.mark.parametrize(
+ "format,version", product(["feather", "parquet"], [None] + SUPPORTED_VERSIONS)
+)
+def test_write_deprecated_version_parameter(tmpdir, format, version):
+ if format == "feather":
+ from pyarrow.feather import read_table
+
+ version = version or 2
+
+ else:
+ from pyarrow.parquet import read_table
+
+ version = version or "2.6"
+
+ filename = os.path.join(str(tmpdir), f"test.{format}")
+ gdf = geopandas.GeoDataFrame(geometry=[box(0, 0, 10, 10)], crs="EPSG:4326")
+ write = getattr(gdf, f"to_{format}")
+
+ if version in SUPPORTED_VERSIONS:
+ with pytest.warns(
+ FutureWarning,
+ match="the `version` parameter has been replaced with `schema_version`",
+ ):
+ write(filename, version=version)
+
+ else:
+ # no warning raised if not one of the captured versions
+ write(filename, version=version)
+
+ table = read_table(filename)
+ metadata = json.loads(table.schema.metadata[b"geo"])
+
+ if version in SUPPORTED_VERSIONS:
+ # version is captured as a parameter
+ assert metadata["version"] == version
+ else:
+ # version is passed to underlying writer
+ assert metadata["version"] == METADATA_VERSION
+
+
@pytest.mark.parametrize("version", ["0.1.0", "0.4.0"])
def test_read_versioned_file(version):
"""
=====================================
geopandas/io/tests/test_file.py
=====================================
@@ -10,6 +10,7 @@ import numpy as np
import pandas as pd
import pytz
+from pandas.api.types import is_datetime64_any_dtype
from pandas.testing import assert_series_equal
from shapely.geometry import Point, Polygon, box
@@ -32,12 +33,14 @@ except ImportError:
try:
import fiona
- FIONA_GE_1814 = Version(fiona.__version__) >= Version(
- "1.8.14"
- ) # datetime roundtrip
+ # 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")
except ImportError:
fiona = False
FIONA_GE_1814 = False
+ FIONA_GE_1821 = False
PYOGRIO_MARK = pytest.mark.skipif(not pyogrio, reason="pyogrio not installed")
@@ -231,6 +234,85 @@ def test_to_file_datetime(tmpdir, driver, ext, time, engine):
assert_series_equal(df["b"], df_read["b"])
+dt_exts = ["gpkg", "geojson"]
+
+
+def write_invalid_date_file(date_str, tmpdir, ext, engine):
+ tempfilename = os.path.join(str(tmpdir), f"test_invalid_datetime.{ext}")
+ df = GeoDataFrame(
+ {
+ "date": ["2014-08-26T10:01:23", "2014-08-26T10:01:23", date_str],
+ "geometry": [Point(1, 1), Point(1, 1), Point(1, 1)],
+ }
+ )
+ # Schema not required for GeoJSON since not typed, but needed for GPKG
+ if ext == "geojson":
+ df.to_file(tempfilename)
+ else:
+ schema = {"geometry": "Point", "properties": {"date": "datetime"}}
+ if engine == "pyogrio" and not fiona:
+ # (use schema to write the invalid date without pandas datetimes
+ pytest.skip("test requires fiona kwarg schema")
+ df.to_file(tempfilename, schema=schema, engine="fiona")
+ return tempfilename
+
+
+ at pytest.mark.parametrize("ext", dt_exts)
+def test_read_file_datetime_invalid(tmpdir, ext, engine):
+ # https://github.com/geopandas/geopandas/issues/2502
+ if not FIONA_GE_1821 and ext == "gpkg":
+ # https://github.com/Toblerity/Fiona/issues/1035
+ pytest.skip("Invalid datetime throws in Fiona<1.8.21")
+
+ date_str = "9999-99-99T00:00:00" # invalid date handled by GDAL
+ tempfilename = write_invalid_date_file(date_str, tmpdir, ext, engine)
+ res = read_file(tempfilename)
+ if ext == "gpkg":
+ assert is_datetime64_any_dtype(res["date"])
+ assert pd.isna(res["date"].iloc[-1])
+ else:
+ assert res["date"].dtype == "object"
+ assert isinstance(res["date"].iloc[-1], str)
+
+
+ at pytest.mark.parametrize("ext", dt_exts)
+def test_read_file_datetime_out_of_bounds_ns(tmpdir, ext, engine):
+ # https://github.com/geopandas/geopandas/issues/2502
+ if ext == "geojson":
+ skip_pyogrio_not_supported(engine)
+
+ date_str = "9999-12-31T00:00:00" # valid to GDAL, not to [ns] format
+ tempfilename = write_invalid_date_file(date_str, tmpdir, ext, engine)
+ res = read_file(tempfilename)
+ # Pandas invalid datetimes are read in as object dtype (strings)
+ assert res["date"].dtype == "object"
+ assert isinstance(res["date"].iloc[0], str)
+
+
+def test_read_file_datetime_mixed_offsets(tmpdir):
+ # https://github.com/geopandas/geopandas/issues/2478
+ tempfilename = os.path.join(str(tmpdir), "test_mixed_datetime.geojson")
+ df = GeoDataFrame(
+ {
+ "date": [
+ "2014-08-26 10:01:23.040001+02:00",
+ "2019-03-07 17:31:43.118999+01:00",
+ ],
+ "geometry": [Point(1, 1), Point(1, 1)],
+ }
+ )
+ df.to_file(tempfilename)
+ # check mixed tz don't crash GH2478
+ res = read_file(tempfilename)
+ if FIONA_GE_1814:
+ # Convert mixed timezones to UTC equivalent
+ assert is_datetime64_any_dtype(res["date"])
+ assert res["date"].dt.tz == pytz.utc
+ else:
+ # old fiona and pyogrio ignore timezones and read as datetimes successfully
+ assert is_datetime64_any_dtype(res["date"])
+
+
@pytest.mark.parametrize("driver,ext", driver_ext_pairs)
def test_to_file_with_point_z(tmpdir, ext, driver, engine):
"""Test that 3D geometries are retained in writes (GH #612)."""
=====================================
geopandas/tests/test_geodataframe.py
=====================================
@@ -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"])
=====================================
geopandas/tests/test_geom_methods.py
=====================================
@@ -1220,6 +1220,24 @@ class TestGeomMethods:
)
assert_geodataframe_equal(test_df, expected_df)
+ @pytest.mark.parametrize("geom_col", ["geom", "geometry"])
+ def test_explode_geometry_name(self, geom_col):
+ s = GeoSeries([MultiPoint([Point(1, 2), Point(2, 3)]), Point(5, 5)])
+ df = GeoDataFrame({"col": [1, 2], geom_col: s}, geometry=geom_col)
+ test_df = df.explode(index_parts=True)
+
+ assert test_df.geometry.name == geom_col
+ assert test_df.geometry.name == test_df._geometry_column_name
+
+ def test_explode_geometry_name_two_geoms(self):
+ s = GeoSeries([MultiPoint([Point(1, 2), Point(2, 3)]), Point(5, 5)])
+ df = GeoDataFrame({"col": [1, 2], "geom": s, "geometry": s}, geometry="geom")
+ test_df = df.explode(index_parts=True)
+
+ assert test_df.geometry.name == "geom"
+ assert test_df.geometry.name == test_df._geometry_column_name
+ assert "geometry" in test_df.columns
+
#
# Test '&', '|', '^', and '-'
#
=====================================
geopandas/tests/test_op_output_types.py
=====================================
@@ -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
=====================================
geopandas/tests/test_pandas_methods.py
=====================================
@@ -655,6 +655,22 @@ def test_df_apply_returning_series(df):
result = df.apply(lambda row: row.value1, axis=1)
assert_series_equal(result, df["value1"].rename(None))
+ # https://github.com/geopandas/geopandas/issues/2480
+ result = df.apply(lambda x: float("NaN"), axis=1)
+ assert result.dtype == "float64"
+ # assert list of nones is not promoted to GeometryDtype
+ result = df.apply(lambda x: None, axis=1)
+ assert result.dtype == "object"
+
+
+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):
=====================================
geopandas/tools/_show_versions.py
=====================================
@@ -86,19 +86,22 @@ def _get_deps_info():
"""
deps = [
"geopandas",
- "pandas",
- "fiona",
+ # required deps
"numpy",
- "shapely",
- "rtree",
+ "pandas",
"pyproj",
+ "shapely",
+ # optional deps
+ "fiona",
+ "geoalchemy2",
+ "geopy",
"matplotlib",
"mapclassify",
- "geopy",
+ "pygeos",
+ "pyogrio",
"psycopg2",
- "geoalchemy2",
"pyarrow",
- "pygeos",
+ "rtree",
]
def get_version(module):
View it on GitLab: https://salsa.debian.org/debian-gis-team/python-geopandas/-/commit/1535f78fa94610e5e93e944a5fc6d003b478320f
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/python-geopandas/-/commit/1535f78fa94610e5e93e944a5fc6d003b478320f
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20220724/595d0d27/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list