Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAINT: avoid most of the warnings coming from dev CI #591

Merged
merged 6 commits into from
Oct 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions libpysal/cg/alpha_shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import numpy as np
import scipy.spatial as spat
from scipy import sparse
from packaging.version import Version

from ..common import requires, jit, HAS_JIT

Expand All @@ -24,7 +25,6 @@

try:
import shapely
from packaging.version import Version

assert Version(shapely.__version__) >= Version("2")

Expand Down Expand Up @@ -715,13 +715,18 @@ def _filter_holes(geoms, points):
"""
Filter hole polygons using a computational geometry solution
"""
import geopandas
if (geoms.interiors.apply(len) > 0).any():
from shapely.geometry import Polygon

# Extract the "shell", or outer ring of the polygon.
shells = geoms.exterior.apply(Polygon)
# Compute which original geometries are within each shell, self-inclusive
inside, outside = shells.sindex.query_bulk(geoms, predicate="within")
if Version(geopandas.__version__) >= Version("0.13"):
inside, outside = shells.sindex.query(geoms, predicate="within")
else:
inside, outside = shells.sindex.query_bulk(geoms, predicate="within")

# Now, create the sparse matrix relating the inner geom (rows)
# to the outer shell (cols) and take the sum.
# A z-order of 1 means the polygon is only inside if its own exterior. This means it's not a hole.
Expand Down
25 changes: 18 additions & 7 deletions libpysal/cg/tests/test_ashapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
from ..alpha_shapes import alpha_shape, alpha_shape_auto
import numpy as np
import os
from packaging.version import Version

try:
import geopandas
from shapely import geometry

GEOPANDAS_EXTINCT = False
GPD_013 = Version(geopandas.__version__) >= Version("0.13")
except ImportError:
GEOPANDAS_EXTINCT = True

Expand Down Expand Up @@ -98,20 +100,29 @@ def test_circles(self):
ashape, radius, centers = alpha_shape_auto(self.vertices, return_circles=True)
np.testing.assert_allclose(radius, self.circle_radii)
np.testing.assert_allclose(centers, self.circle_verts)

def test_holes(self):
np.random.seed(seed=100)
points = np.random.rand(1000, 2)*100
points = np.random.rand(1000, 2) * 100
inv_alpha = 3.5
geoms = alpha_shape(points, 1/inv_alpha)
geoms = alpha_shape(points, 1 / inv_alpha)
assert len(geoms) == 1
holes = geopandas.GeoSeries(geoms.interiors.explode()).reset_index(drop=True)
assert len(holes) == 30
# No holes are within the shape (shape has holes already)
result = geoms.sindex.query_bulk(holes.centroid, predicate='within')
assert result.shape == (2,0)
if GPD_013:
result = geoms.sindex.query(holes.centroid, predicate="within")
else:
result = geoms.sindex.query_bulk(holes.centroid, predicate="within")

assert result.shape == (2, 0)
# All holes are within the exterior
shell = geopandas.GeoSeries(geoms.exterior.apply(geometry.Polygon))
within, outside = shell.sindex.query_bulk(holes.centroid, predicate='within')
if GPD_013:
within, outside = shell.sindex.query(holes.centroid, predicate="within")
else:
within, outside = shell.sindex.query_bulk(
holes.centroid, predicate="within"
)
assert (outside == 0).all()
np.testing.assert_array_equal(within, np.arange(30))
np.testing.assert_array_equal(within, np.arange(30))
18 changes: 16 additions & 2 deletions libpysal/graph/_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import warnings

import geopandas
import numpy as np
import pandas as pd
Expand Down Expand Up @@ -106,11 +108,23 @@ def _neighbor_dict_to_edges(neighbors, weights=None):
that the any self-loops have a weight of zero.
"""
idxs = pd.Series(neighbors).explode()
idxs = idxs.fillna(pd.Series(idxs.index, index=idxs.index)) # self-loops
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
"Downcasting object dtype arrays on .fillna, .ffill, .bfill ",
FutureWarning,
)
idxs = idxs.fillna(pd.Series(idxs.index, index=idxs.index)) # self-loops
heads, tails = idxs.index.values, idxs.values
tails = tails.astype(heads.dtype)
if weights is not None:
data_array = pd.Series(weights).explode().fillna(0).values
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
"Downcasting object dtype arrays on .fillna, .ffill, .bfill ",
FutureWarning,
)
data_array = pd.Series(weights).explode().fillna(0).values
if not pd.api.types.is_numeric_dtype(data_array):
data_array = pd.to_numeric(data_array)
else:
Expand Down
2 changes: 1 addition & 1 deletion libpysal/graph/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ def nonzero(self):
return (self._adjacency.drop(self.isolates) > 0).sum()

def asymmetry(self, intrinsic=True):
"""Asymmetry check.
r"""Asymmetry check.

Parameters
----------
Expand Down
29 changes: 13 additions & 16 deletions libpysal/io/iohandlers/pyDbfIO.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
class DBF(tables.DataTable):
"""PySAL DBF Reader/Writer. This DBF handler implements the PySAL DataTable
interface and initializes an instance of the PySAL's DBF handler.

Parameters
-----------
dataPath : str
Path to file, including file name and extension.
mode : str
Mode for file interaction; either ``'r'`` or ``'w'``.

Attributes
----------
header : list
Expand All @@ -41,7 +41,7 @@ class DBF(tables.DataTable):
>>> dbf = libpysal.io.open(libpysal.examples.get_path('juvenile.dbf'), 'r')
>>> dbf.header
['ID', 'X', 'Y']

>>> dbf.field_spec
[('N', 9, 0), ('N', 9, 0), ('N', 9, 0)]

Expand All @@ -51,7 +51,6 @@ class DBF(tables.DataTable):
MODES = ["r", "w"]

def __init__(self, *args, **kwargs):

tables.DataTable.__init__(self, *args, **kwargs)

if self.mode == "r":
Expand Down Expand Up @@ -115,12 +114,12 @@ def __init__(self, *args, **kwargs):

def __len__(self) -> int:
"""

Raises
------
IOError
Raised when a file is open ``'w'`` mode.

"""

if self.mode != "r":
Expand All @@ -135,12 +134,12 @@ def seek(self, i):

def _get_col(self, key: str) -> list:
"""Return the column vector.

Raises
------
AttributeError
Raised when a field does not exist in the header.

"""

if key not in self._col_index:
Expand Down Expand Up @@ -196,7 +195,6 @@ def _get_col(self, key: str) -> list:
return col

def read_record(self, i: int) -> list:

self.seek(i)

rec = list(struct.unpack(self.record_fmt, self.f.read(self.record_size)))
Expand Down Expand Up @@ -246,12 +244,12 @@ def read_record(self, i: int) -> list:

def _read(self) -> Union[list, None]:
"""

Raises
------
IOError
Raised when a file is open ``'w'`` mode.

"""

if self.mode != "r":
Expand All @@ -267,14 +265,14 @@ def _read(self) -> Union[list, None]:

def write(self, obj: list):
"""

Raises
------
IOError
Raised when a file is open ``'r'`` mode.
TypeError
Raised when a row length and header length are not equivalent.

"""

self._complain_ifclosed(self.closed)
Expand Down Expand Up @@ -326,7 +324,6 @@ def flush(self):
self.f.flush()

def close(self):

if self.mode == "w":
self.flush()
# End of file
Expand All @@ -337,14 +334,14 @@ def close(self):

def _firstWrite(self):
"""

Raises
------
IOError
Raised when there is no specified header.
IOError
Raised when there is no field specification.

"""

if not self.header:
Expand Down
30 changes: 16 additions & 14 deletions libpysal/io/iohandlers/tests/test_gwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .... import examples as pysal_examples
import tempfile
import os
import pytest
import warnings


Expand Down Expand Up @@ -35,20 +36,21 @@ def test_seek(self):
# see issue #153.
# Added back by CRS,
def test_write(self):
w = self.obj.read()
f = tempfile.NamedTemporaryFile(suffix=".gwt")
fname = f.name
f.close()
o = psopen(fname, "w")
# copy the shapefile and ID variable names from the old gwt.
# this is only available after the read() method has been called.
# o.shpName = self.obj.shpName
# o.varName = self.obj.varName
o.write(w)
o.close()
wnew = psopen(fname, "r").read()
self.assertEqual(wnew.pct_nonzero, w.pct_nonzero)
os.remove(fname)
with pytest.warns(RuntimeWarning, match="DBF relating to GWT was not found"):
w = self.obj.read()
f = tempfile.NamedTemporaryFile(suffix=".gwt")
fname = f.name
f.close()
o = psopen(fname, "w")
# copy the shapefile and ID variable names from the old gwt.
# this is only available after the read() method has been called.
# o.shpName = self.obj.shpName
# o.varName = self.obj.varName
o.write(w)
o.close()
wnew = psopen(fname, "r").read()
self.assertEqual(wnew.pct_nonzero, w.pct_nonzero)
os.remove(fname)


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion libpysal/weights/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def test_full2W(self):
for i in range(len(a)):
for j in range(len(a[i])):
if i != j:
a[i, j] = np.random.random(1)
a[i, j] = np.random.random(1)[0]
w = util.full2W(a)
np.testing.assert_array_equal(w.full()[0], a)
ids = ["myID0", "myID1", "myID2", "myID3"]
Expand Down
34 changes: 13 additions & 21 deletions libpysal/weights/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
try:
import geopandas as gpd

GPD_08 = Version(gpd.__version__) >= Version("0.8.0")
GPD_013 = Version(gpd.__version__) >= Version("0.13.0")
except ImportError:
warn("geopandas not available. Some functionality will be disabled.")

Expand Down Expand Up @@ -1653,28 +1653,20 @@ def fuzzy_contiguity(
gdf.set_geometry("_buffer", inplace=True)

neighbors = {}
if GPD_08:
if GPD_013:
# query tree based on set predicate
inp, res = gdf.sindex.query_bulk(gdf.geometry, predicate=predicate)
# remove self hits
itself = inp == res
inp = inp[~itself]
res = res[~itself]

# extract index values of neighbors
for i, ix in enumerate(gdf.index):
ids = gdf.index[res[inp == i]].tolist()
neighbors[ix] = ids
inp, res = gdf.sindex.query(gdf.geometry, predicate=predicate)
else:
if predicate != "intersects":
raise ValueError(f"Predicate `{predicate}` requires geopandas >= 0.8.0.")
tree = gdf.sindex
for i, (ix, geom) in enumerate(gdf.geometry.iteritems()):
hits = list(tree.intersection(geom.bounds))
hits.remove(i)
possible = gdf.iloc[hits]
ids = possible[possible.intersects(geom)].index.tolist()
neighbors[ix] = ids
inp, res = gdf.sindex.query_bulk(gdf.geometry, predicate=predicate)
# remove self hits
itself = inp == res
inp = inp[~itself]
res = res[~itself]

# extract index values of neighbors
for i, ix in enumerate(gdf.index):
ids = gdf.index[res[inp == i]].tolist()
neighbors[ix] = ids

if buffering:
gdf.set_geometry(old_geometry_name, inplace=True)
Expand Down
18 changes: 18 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,21 @@ exclude_lines = [
]
ignore_errors = true
omit = ["libpysal/tests/*", "docs/conf.py"]

[tool.pytest.ini_options]
filterwarnings = [
"ignore:The numba package is used",
"ignore:numba cannot be imported",
"ignore:Numba not imported",
"ignore:The weights matrix is not fully connected",
"ignore:You are trying to build a full W object from",
"ignore:Multiple layers detected. Using first layer as default",
"ignore:Geometry is in a geographic CRS",
"ignore:`use_index` defaults to False",
"ignore:Objects based on the `Geometry` class will deprecated",
"ignore:PolygonLocator is deprecated",
"ignore:SegmentGrid is deprecated",
"ignore:In the next version of libpysal, observations with no neighbors",
"ignore:divide by zero encountered",
"ignore:invalid value encountered",
]
Loading