Skip to content
Commits on Source (5)
Changes
=======
Version 0.6.3 (February 6, 2020)
---------------------------------
Small bug-fix release:
- Compatibility with Shapely 1.7 and pandas 1.0 (#1244).
- Fix `GeoDataFrame.fillna` to accept non-geometry values again when there are
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)
---------------------------------
......
python-geopandas (0.6.2-3) UNRELEASED; urgency=medium
python-geopandas (0.6.3-1) unstable; urgency=medium
* Team upload.
* New upstream release.
* Bump Standards-Version to 4.5.0, no changes.
* Drop pysal build dependency.
-- Bas Couwenberg <sebastic@debian.org> Sat, 25 Jan 2020 11:07:10 +0100
-- Bas Couwenberg <sebastic@debian.org> Fri, 07 Feb 2020 06:41:49 +0100
python-geopandas (0.6.2-2) unstable; urgency=medium
......
......@@ -22,7 +22,6 @@ Build-Depends: debhelper (>= 9),
python3-pandas,
python3-psycopg2,
python3-pyproj,
python3-pysal (>= 1.11.2-3~),
python3-pytest-cov,
python3-pytest,
python3-rtree,
......
......@@ -9,6 +9,7 @@ import six
PANDAS_GE_024 = str(pd.__version__) >= LooseVersion("0.24.0")
PANDAS_GE_025 = str(pd.__version__) >= LooseVersion("0.25.0")
PANDAS_GE_10 = str(pd.__version__) >= LooseVersion("0.26.0.dev")
# -----------------------------------------------------------------------------
......
......@@ -22,8 +22,8 @@ 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 = " (tag: v0.6.2, 0.6.x)"
git_full = "34fe94357b8131afb49da76b1e5b14d9477f9e37"
git_refnames = " (tag: v0.6.3, 0.6.x)"
git_full = "280195d3ee0208c5ff8d25b2982b71bf5f04e9f1"
keywords = {"refnames": git_refnames, "full": git_full}
return keywords
......
......@@ -13,7 +13,7 @@ from shapely.geometry.base import BaseGeometry
import shapely.ops
import shapely.wkt
from ._compat import PANDAS_GE_024, Iterable
from ._compat import PANDAS_GE_024, PANDAS_GE_10, Iterable
class GeometryDtype(ExtensionDtype):
......@@ -23,10 +23,16 @@ class GeometryDtype(ExtensionDtype):
@classmethod
def construct_from_string(cls, string):
if string == cls.name:
if not isinstance(string, str):
raise TypeError(
"'construct_from_string' expects a string, got {}".format(type(string))
)
elif string == cls.name:
return cls()
else:
raise TypeError("Cannot construct a '{}' from '{}'".format(cls, string))
raise TypeError(
"Cannot construct a '{}' from '{}'".format(cls.__name__, string)
)
@classmethod
def construct_array_type(cls):
......@@ -230,7 +236,10 @@ def _binary_geo(op, left, right):
# intersection can return empty GeometryCollections, and if the
# result are only those, numpy will coerce it to empty 2D array
data = np.empty(len(left), dtype=object)
data[:] = [getattr(s, op)(right) if s and right else None for s in left.data]
data[:] = [
getattr(s, op)(right) if s is not None and right is not None else None
for s in left.data
]
return GeometryArray(data)
elif isinstance(right, GeometryArray):
if len(left) != len(right):
......@@ -240,7 +249,9 @@ def _binary_geo(op, left, right):
raise ValueError(msg)
data = np.empty(len(left), dtype=object)
data[:] = [
getattr(this_elem, op)(other_elem) if this_elem and other_elem else None
getattr(this_elem, op)(other_elem)
if this_elem is not None and other_elem is not None
else None
for this_elem, other_elem in zip(left.data, right.data)
]
return GeometryArray(data)
......@@ -432,12 +443,21 @@ class GeometryArray(ExtensionArray):
def __getitem__(self, idx):
if isinstance(idx, numbers.Integral):
return self.data[idx]
elif isinstance(idx, (Iterable, slice)):
# array-like, slice
if PANDAS_GE_10:
# for pandas >= 1.0, validate and convert IntegerArray/BooleanArray
# to numpy array, pass-through non-array-like indexers
idx = pd.api.indexers.check_array_indexer(self, idx)
if isinstance(idx, (Iterable, slice)):
return GeometryArray(self.data[idx])
else:
raise TypeError("Index type not supported", idx)
def __setitem__(self, key, value):
if PANDAS_GE_10:
# for pandas >= 1.0, validate and convert IntegerArray/BooleanArray
# keys to numpy array, pass-through non-array-like indexers
key = pd.api.indexers.check_array_indexer(self, key)
if isinstance(value, pd.Series):
value = value.values
if isinstance(value, (list, np.ndarray)):
......@@ -836,18 +856,17 @@ class GeometryArray(ExtensionArray):
if method is not None:
raise NotImplementedError("fillna with a method is not yet supported")
mask = self.isna()
new_values = self.copy()
if mask.any():
# fill with value
if _isna(value):
value = None
elif not isinstance(value, BaseGeometry):
raise NotImplementedError(
"fillna currently only supports filling with a scalar geometry"
)
mask = self.isna()
new_values = self.copy()
if mask.any():
# fill with value
new_values = new_values._fill(mask, value)
return new_values
......
import subprocess
import sys
from geopandas._compat import PANDAS_GE_10
def test_no_additional_imports():
# test that 'import geopandas' does not import any of the optional or
# development dependencies
blacklist = {
"pytest",
"py",
"ipython",
# 'matplotlib', # matplotlib gets imported by pandas, see below
"descartes",
"mapclassify",
# 'rtree', # rtree actually gets imported if installed
"sqlalchemy",
"psycopg2",
"geopy",
}
if PANDAS_GE_10:
# pandas > 0.25 stopped importing matplotlib by default
blacklist.add("matplotlib")
code = """
import sys
import geopandas
blacklist = {'pytest', 'py', 'ipython',
'matplotlib' 'descartes','mapclassify',
# 'rtree', # rtree actually gets imported if installed
'sqlalchemy', 'psycopg2', 'geopy'}
blacklist = {0!r}
mods = blacklist & set(m.split('.')[0] for m in sys.modules)
if mods:
sys.stderr.write('err: geopandas should not import: {}'.format(', '.join(mods)))
sys.stderr.write('err: geopandas should not import: {{}}'.format(', '.join(mods)))
sys.exit(len(mods))
"""
""".format(
blacklist
)
call = [sys.executable, "-c", code]
# TODO(py3) update with subprocess.run once python 2.7 is dropped
returncode = subprocess.call(call, stderr=subprocess.STDOUT)
......
......@@ -322,7 +322,7 @@ def test_select_dtypes(df):
# Missing values
def test_fillna(s):
def test_fillna(s, df):
s2 = GeoSeries([Point(0, 0), None, Point(2, 2)])
res = s2.fillna(Point(1, 1))
assert_geoseries_equal(res, s)
......@@ -332,6 +332,21 @@ def test_fillna(s):
res = s2.fillna(np.nan)
assert_geoseries_equal(res, s2)
# raise exception if trying to fill missing geometry w/ non-geometry
df2 = df.copy()
df2["geometry"] = s2
res = df2.fillna(Point(1, 1))
assert_geodataframe_equal(res, df)
with pytest.raises(NotImplementedError):
df2.fillna(0)
# allow non-geometry fill value if there are no missing values
# https://github.com/geopandas/geopandas/issues/1149
df3 = df.copy()
df3.loc[0, "value1"] = np.nan
res = df3.fillna(0)
assert_geodataframe_equal(res.astype({"value1": "int64"}), df)
def test_dropna():
s2 = GeoSeries([Point(0, 0), None, Point(2, 2)])
......