From 0601a8652548acbdb54a32dfd58a43ab311e0276 Mon Sep 17 00:00:00 2001 From: Martin Fleischmann Date: Wed, 22 Nov 2023 21:05:38 +0100 Subject: [PATCH] lint and remove compat --- momepy/coins.py | 4 +-- momepy/dimension.py | 6 ++-- momepy/distribution.py | 8 +++-- momepy/diversity.py | 2 +- momepy/elements.py | 60 ++++++++++----------------------- momepy/preprocessing.py | 54 ++++++----------------------- momepy/tests/test_elements.py | 9 ----- momepy/tests/test_graph.py | 3 -- momepy/tests/test_preprocess.py | 23 ++----------- momepy/tests/test_utils.py | 4 --- momepy/utils.py | 10 +++--- momepy/weights.py | 2 +- 12 files changed, 49 insertions(+), 136 deletions(-) diff --git a/momepy/coins.py b/momepy/coins.py index 7c60d41c..f044fc8f 100644 --- a/momepy/coins.py +++ b/momepy/coins.py @@ -170,7 +170,7 @@ def _get_links(self): p2.append(item) - self.result = list(zip(range(len(p1)), p1, p2)) + self.result = list(zip(range(len(p1)), p1, p2, strict=True)) for a in self.result: n = a[0] @@ -371,7 +371,7 @@ def _list_to_tuple(line): def _list_to_pairs(in_list): """Split a line at every point.""" tmp_list = [list(point) for point in in_list] - return [list(pair) for pair in zip(tmp_list, tmp_list[1:])] + return [list(pair) for pair in zip(tmp_list, tmp_list[1:], strict=True)] def _compute_angle(point1, point2): diff --git a/momepy/dimension.py b/momepy/dimension.py index 0cfee7f4..eac95128 100644 --- a/momepy/dimension.py +++ b/momepy/dimension.py @@ -546,7 +546,7 @@ def __init__( end_markers = [] lengths = shapely.length(lines) - for ix, (line, length) in enumerate(zip(lines, lengths)): + for ix, (line, length) in enumerate(zip(lines, lengths, strict=True)): pts = shapely.line_interpolate_point( line, np.linspace(0, length, num=int((length) // distance)) ) @@ -560,7 +560,7 @@ def __init__( ids += [ix] * 2 ticks = [] - for num, (pt, end) in enumerate(zip(list_points, end_markers), 1): + for num, (pt, end) in enumerate(zip(list_points, end_markers, strict=True), 1): if end: ticks.append([pt, pt]) ticks.append([pt, pt]) @@ -587,7 +587,7 @@ def __init__( min_distances = [] min_inds = [] - for dis, ind in zip(dist_per_res, inp_per_res): + for dis, ind in zip(dist_per_res, inp_per_res, strict=True): min_distances.append(np.min(dis)) min_inds.append(ind[np.argmin(dis)]) diff --git a/momepy/distribution.py b/momepy/distribution.py index 9811d45d..13f4c79c 100644 --- a/momepy/distribution.py +++ b/momepy/distribution.py @@ -70,7 +70,9 @@ def _dist(a, b): bboxes = shapely.minimum_rotated_rectangle(gdf.geometry) for geom, bbox in tqdm( - zip(gdf.geometry, bboxes), total=gdf.shape[0], disable=not verbose + zip(gdf.geometry, bboxes, strict=True), + total=gdf.shape[0], + disable=not verbose, ): if geom.geom_type in ["Polygon", "MultiPolygon", "LinearRing"]: bbox = list(bbox.exterior.coords) @@ -793,7 +795,9 @@ def __init__( print("Spatial weights ready...") if verbose else None self.sw = spatial_weights - patches = dict(zip(gdf[unique_id], spatial_weights.component_labels)) + patches = dict( + zip(gdf[unique_id], spatial_weights.component_labels, strict=True) + ) for uid in tqdm( self.id, diff --git a/momepy/diversity.py b/momepy/diversity.py index 880df5fc..a53725b9 100644 --- a/momepy/diversity.py +++ b/momepy/diversity.py @@ -685,7 +685,7 @@ def p(n, sum_n): counts.update(data.value_counts()) else: sample_bins = mc.UserDefined(data, bins) - counts = dict(zip(bins, sample_bins.counts)) + counts = dict(zip(bins, sample_bins.counts, strict=True)) return -sum(p(n, sum(counts.values())) for n in counts.values() if n != 0) diff --git a/momepy/elements.py b/momepy/elements.py index 6b71fd79..0d567954 100644 --- a/momepy/elements.py +++ b/momepy/elements.py @@ -9,7 +9,6 @@ import numpy as np import pandas as pd import shapely -from packaging.version import Version from scipy.spatial import Voronoi from shapely.geometry.base import BaseGeometry from shapely.ops import polygonize @@ -25,8 +24,6 @@ "get_network_ratio", ] -GPD_10 = Version(gpd.__version__) >= Version("0.10") - def buffered_limit(gdf, buffer=100): """ @@ -241,7 +238,7 @@ def __init__( n_chunks, ) else: - if isinstance(limit, (gpd.GeoSeries, gpd.GeoDataFrame)): + if isinstance(limit, gpd.GeoSeries | gpd.GeoDataFrame): limit = limit.unary_union bounds = shapely.bounds(limit) @@ -275,10 +272,7 @@ def _morphological_tessellation( objects.loc[mask, objects.geometry.name] = objects[mask].buffer( -shrink, cap_style=2, join_style=2 ) - if GPD_10: - objects = objects.reset_index(drop=True).explode(ignore_index=True) - else: - objects = objects.reset_index(drop=True).explode().reset_index(drop=True) + objects = objects.reset_index(drop=True).explode(ignore_index=True) objects = objects.set_index(unique_id) print("Generating input point array...") if verbose else None @@ -331,7 +325,7 @@ def _dense_point_array(self, geoms, distance, index): else: lines = geoms lengths = shapely.length(lines) - for ix, line, length in zip(index, lines, lengths): + for ix, line, length in zip(index, lines, lengths, strict=True): if length > distance: # some polygons might have collapsed pts = shapely.line_interpolate_point( line, @@ -621,45 +615,28 @@ def __init__(self, tessellation, edges, buildings, id_name, unique_id): gpd.GeoDataFrame(geometry=edges.buffer(0.001)), how="difference", ) - cut = cut.explode(ignore_index=True) if GPD_10 else cut.explode() - + cut = cut.explode(ignore_index=True) weights = libpysal.weights.Queen.from_dataframe(cut, silence_warnings=True) cut["component"] = weights.component_labels buildings_c = buildings.copy() buildings_c.geometry = buildings_c.representative_point() # make points - if GPD_10: - centroids_temp_id = gpd.sjoin( - buildings_c, - cut[[cut.geometry.name, "component"]], - how="left", - predicate="within", - ) - else: - centroids_temp_id = gpd.sjoin( - buildings_c, - cut[[cut.geometry.name, "component"]], - how="left", - op="within", - ) + centroids_temp_id = gpd.sjoin( + buildings_c, + cut[[cut.geometry.name, "component"]], + how="left", + predicate="within", + ) cells_copy = tessellation[[unique_id, tessellation.geometry.name]].merge( centroids_temp_id[[unique_id, "component"]], on=unique_id, how="left" ) - if GPD_10: - blocks = cells_copy.dissolve(by="component").explode(ignore_index=True) - else: - blocks = ( - cells_copy.dissolve(by="component").explode().reset_index(drop=True) - ) + blocks = cells_copy.dissolve(by="component").explode(ignore_index=True) blocks[id_name] = range(len(blocks)) blocks = blocks[[id_name, blocks.geometry.name]] - if GPD_10: - centroids_w_bl_id2 = gpd.sjoin( - buildings_c, blocks, how="left", predicate="within" - ) - else: - centroids_w_bl_id2 = gpd.sjoin(buildings_c, blocks, how="left", op="within") + centroids_w_bl_id2 = gpd.sjoin( + buildings_c, blocks, how="left", predicate="within" + ) self.buildings_id = centroids_w_bl_id2[id_name] @@ -823,7 +800,7 @@ def get_node_id( edges = edges.set_index(edge_id) centroids = objects.centroid for eid, centroid in tqdm( - zip(objects[edge_id], centroids), + zip(objects[edge_id], centroids, strict=True), total=objects.shape[0], disable=not verbose, ): @@ -844,7 +821,9 @@ def get_node_id( elif edge_keys is not None and edge_values is not None: for edge_i, edge_r, geom in tqdm( - zip(objects[edge_keys], objects[edge_values], objects.geometry), + zip( + objects[edge_keys], objects[edge_values], objects.geometry, strict=True + ), total=objects.shape[0], disable=not verbose, ): @@ -903,9 +882,6 @@ def get_network_ratio(df, edges, initial_buffer=500): 4 [26] [1] """ - if not GPD_10: - raise ImportError("`get_network_ratio` requires geopandas 0.10 or newer.") - (df_ix, edg_ix), dist = edges.sindex.nearest( df.geometry, max_distance=initial_buffer, return_distance=True ) diff --git a/momepy/preprocessing.py b/momepy/preprocessing.py index 7672f36b..2acfb7fe 100644 --- a/momepy/preprocessing.py +++ b/momepy/preprocessing.py @@ -10,7 +10,6 @@ import numpy as np import pandas as pd import shapely -from packaging.version import Version from scipy.signal import find_peaks from scipy.stats import gaussian_kde from shapely.geometry import LineString, Point @@ -30,9 +29,6 @@ "FaceArtifacts", ] -GPD_10 = Version(gpd.__version__) >= Version("0.10") -GPD_09 = Version(gpd.__version__) >= Version("0.9") - def preprocess( buildings, size=30, compactness=0.2, islands=True, loops=2, verbose=True @@ -80,11 +76,7 @@ def preprocess( GeoDataFrame containing preprocessed geometry """ blg = buildings.copy() - if GPD_10: - blg = blg.explode(ignore_index=True) - else: - blg = blg.explode() - blg.reset_index(drop=True, inplace=True) + blg = blg.explode(ignore_index=True) for loop in range(0, loops): print("Loop", loop + 1, f"out of {loops}.") if verbose else None blg.reset_index(inplace=True, drop=True) @@ -182,13 +174,10 @@ def remove_false_nodes(gdf): momepy.extend_lines momepy.close_gaps """ - if isinstance(gdf, (gpd.GeoDataFrame, gpd.GeoSeries)): + if isinstance(gdf, gpd.GeoDataFrame | gpd.GeoSeries): # explode to avoid MultiLineStrings # reset index due to the bug in GeoPandas explode - if GPD_10: - df = gdf.reset_index(drop=True).explode(ignore_index=True) - else: - df = gdf.reset_index(drop=True).explode().reset_index(drop=True) + df = gdf.reset_index(drop=True).explode(ignore_index=True) # get underlying shapely geometry geom = df.geometry.array @@ -242,10 +231,7 @@ def remove_false_nodes(gdf): # remove incorrect geometries and append fixed versions df = df.drop(merge) - if GPD_10: - final = gpd.GeoSeries(new).explode(ignore_index=True) - else: - final = gpd.GeoSeries(new).explode().reset_index(drop=True) + final = gpd.GeoSeries(new).explode(ignore_index=True) if isinstance(gdf, gpd.GeoDataFrame): return pd.concat( [ @@ -472,10 +458,7 @@ def extend_lines(gdf, tolerance, target=None, barrier=None, extension=0): """ # explode to avoid MultiLineStrings # reset index due to the bug in GeoPandas explode - if GPD_10: - df = gdf.reset_index(drop=True).explode(ignore_index=True) - else: - df = gdf.reset_index(drop=True).explode().reset_index(drop=True) + df = gdf.reset_index(drop=True).explode(ignore_index=True) if target is None: target = df @@ -758,10 +741,7 @@ def _selecting_rabs_from_poly( rab["rab_diameter"] = rab[["deltax", "deltay"]].max(axis=1) # selecting the adjacent areas that are of smaller than itself - if GPD_10: - rab_adj = gpd.sjoin(gdf, rab, predicate="intersects") - else: - rab_adj = gpd.sjoin(gdf, rab, op="intersects") + rab_adj = gpd.sjoin(gdf, rab, predicate="intersects") area_right = area_col + "_right" area_left = area_col + "_left" @@ -870,16 +850,10 @@ def _selecting_incoming_lines(rab_multipolygons, edges, angle_threshold=0): is used to select the line to be extended further. """ # selecting the lines that are touching but not covered by - if GPD_10: - touching = gpd.sjoin(edges, rab_multipolygons, predicate="touches") - edges_idx, rabs_idx = rab_multipolygons.sindex.query_bulk( - edges.geometry, predicate="covered_by" - ) - else: - touching = gpd.sjoin(edges, rab_multipolygons, op="touches") - edges_idx, rabs_idx = rab_multipolygons.sindex.query_bulk( - edges.geometry, op="covered_by" - ) + touching = gpd.sjoin(edges, rab_multipolygons, predicate="touches") + edges_idx, rabs_idx = rab_multipolygons.sindex.query_bulk( + edges.geometry, predicate="covered_by" + ) idx_drop = edges.index.take(edges_idx) touching_idx = touching.index ls = list(set(touching_idx) - set(idx_drop)) @@ -1035,12 +1009,6 @@ def roundabout_simplification( GeoDataFrame with an updated geometry and an additional column labeling modified edges. """ - if not GPD_09: - raise ImportError( - "`roundabout_simplification` requires geopandas 0.9.0 or newer. " - f"Your current version is {gpd.__version__}." - ) - if len(edges[edges.geom_type != "LineString"]) > 0: raise TypeError( "Only LineString geometries are allowed. " @@ -1223,7 +1191,7 @@ def __init__( # find index (in linspace) of highest peak highest_peak_index = self.peaks[highest_peak_listindex] # define all possible peak ranges fitting our definition - peak_bounds = list(zip(self.peaks, self.peaks[1:])) + peak_bounds = list(zip(self.peaks, self.peaks[1:], strict=True)) peak_bounds_accepted = [b for b in peak_bounds if highest_peak_index in b] # find all valleys that lie between two peaks valleys_accepted = [ diff --git a/momepy/tests/test_elements.py b/momepy/tests/test_elements.py index b8a9cf04..dc9569a6 100644 --- a/momepy/tests/test_elements.py +++ b/momepy/tests/test_elements.py @@ -12,10 +12,6 @@ import momepy as mm -# https://github.com/geopandas/geopandas/issues/2282 -GPD_REGR = Version("0.10.2") < Version(gpd.__version__) < Version("0.11") -GPD_10 = Version(gpd.__version__) >= Version("0.10") - class TestElements: def setup_method(self): @@ -152,7 +148,6 @@ def test_get_network_id_duplicate(self): buildings_id = mm.get_network_id(self.df_buildings, self.df_streets, "nID") assert not buildings_id.isna().any() - @pytest.mark.skipif(GPD_REGR, reason="regression in geopandas") def test_get_node_id(self): nx = mm.gdf_to_nx(self.df_streets) nodes, edges = mm.nx_to_gdf(nx) @@ -162,8 +157,6 @@ def test_get_node_id(self): ids = mm.get_node_id(self.df_buildings, nodes, edges, "nodeID", "nID") assert not ids.isna().any() - @pytest.mark.skipif(GPD_REGR, reason="regression in geopandas") - @pytest.mark.skipif(not GPD_10, reason="requires sindex.nearest") def test_get_node_id_ratio(self): nx = mm.gdf_to_nx(self.df_streets) nodes, edges = mm.nx_to_gdf(nx) @@ -219,7 +212,6 @@ def test_enclosures(self): encl = mm.enclosures(self.df_streets, limit=gpd.GeoSeries([limit]), clip=True) assert len(encl) == 18 - @pytest.mark.skipif(not GPD_10, reason="requires sindex.nearest") def test_get_network_ratio(self): convex_hull = self.df_streets.unary_union.convex_hull enclosures = mm.enclosures(self.df_streets, limit=gpd.GeoSeries([convex_hull])) @@ -246,7 +238,6 @@ def test_get_network_ratio(self): for i, idx in enumerate(expected_tail): assert sorted(links2.edgeID_keys.tail(5).iloc[i]) == sorted(idx) - @pytest.mark.skipif(GPD_10, reason="requires sindex.nearest") def test_get_network_ratio_error(self): convex_hull = self.df_streets.unary_union.convex_hull enclosures = mm.enclosures(self.df_streets, limit=gpd.GeoSeries([convex_hull])) diff --git a/momepy/tests/test_graph.py b/momepy/tests/test_graph.py index 0e32bade..38658f2a 100644 --- a/momepy/tests/test_graph.py +++ b/momepy/tests/test_graph.py @@ -5,8 +5,6 @@ import momepy as mm -NX_26 = Version(nx.__version__) < Version("2.6") - class TestGraph: def setup_method(self): @@ -171,7 +169,6 @@ def test_mean_nodes(self): == edge ) - @pytest.mark.skipif(NX_26, reason="networkx<2.6 has a bug") def test_clustering(self): net = mm.clustering(self.network) check = 0.05555555555555555 diff --git a/momepy/tests/test_preprocess.py b/momepy/tests/test_preprocess.py index 6807e4d2..fed47961 100644 --- a/momepy/tests/test_preprocess.py +++ b/momepy/tests/test_preprocess.py @@ -9,9 +9,6 @@ import momepy as mm -GPD_10 = Version(gpd.__version__) >= Version("0.10") -GPD_09 = Version(gpd.__version__) >= Version("0.9") - class TestPreprocessing: def setup_method(self): @@ -45,11 +42,8 @@ def test_remove_false_nodes(self): fixed_series = mm.remove_false_nodes(self.false_network.geometry) assert len(fixed_series) == 56 assert isinstance(fixed_series, gpd.GeoSeries) - # assert self.false_network.crs.equals(fixed_series.crs) GeoPandas 0.8 BUG - if GPD_10: - multiindex = self.false_network.explode(index_parts=True) - else: - multiindex = self.false_network.explode() + assert self.false_network.crs.equals(fixed_series.crs) + multiindex = self.false_network.explode(index_parts=True) fixed_multiindex = mm.remove_false_nodes(multiindex) assert len(fixed_multiindex) == 56 assert isinstance(fixed, gpd.GeoDataFrame) @@ -132,26 +126,16 @@ def test_extend_lines(self): assert ext5.length.sum() > gdf.length.sum() assert ext5.length.sum() == pytest.approx(6.2, rel=1e-3) - @pytest.mark.skipif(GPD_09, reason="requires geopandas <0.9") - def test_roundabout_simplification_gpd_error(self): - with pytest.raises( - ImportError, match="`roundabout_simplification` requires geopandas 0.9.0" - ): - mm.roundabout_simplification(self.df_streets_rabs) - - @pytest.mark.skipif(not GPD_09, reason="requires geopandas 0.9+") def test_roundabout_simplification_point_error(self): point_df = gpd.GeoDataFrame({"nID": [0]}, geometry=[Point(0, 0)]) with pytest.raises(TypeError, match="Only LineString geometries are allowed."): mm.roundabout_simplification(point_df) - @pytest.mark.skipif(not GPD_09, reason="requires geopandas 0.9+") def test_roundabout_simplification_default(self): check = mm.roundabout_simplification(self.df_streets_rabs) assert len(check) == 65 assert len(self.df_streets_rabs) == 88 # checking that nothing has changed - @pytest.mark.skipif(not GPD_09, reason="requires geopandas 0.9+") def test_roundabout_simplification_high_circom_threshold(self): check = mm.roundabout_simplification( self.df_streets_rabs, self.df_rab_polys, circom_threshold=0.97 @@ -159,7 +143,6 @@ def test_roundabout_simplification_high_circom_threshold(self): assert len(check) == 77 assert len(self.df_streets_rabs) == 88 - @pytest.mark.skipif(not GPD_09, reason="requires geopandas 0.9+") def test_roundabout_simplification_low_area_threshold(self): check = mm.roundabout_simplification( self.df_streets_rabs, self.df_rab_polys, area_threshold=0.8 @@ -167,7 +150,6 @@ def test_roundabout_simplification_low_area_threshold(self): assert len(check) == 67 assert len(self.df_streets_rabs) == 88 - @pytest.mark.skipif(not GPD_09, reason="requires geopandas 0.9+") def test_roundabout_simplification_exclude_adjacent(self): check = mm.roundabout_simplification( self.df_streets_rabs, self.df_rab_polys, include_adjacent=False @@ -175,7 +157,6 @@ def test_roundabout_simplification_exclude_adjacent(self): assert len(check) == 88 assert len(self.df_streets_rabs) == 88 - @pytest.mark.skipif(not GPD_09, reason="requires geopandas 0.9+") def test_roundabout_simplification_center_type_mean(self): check = mm.roundabout_simplification( self.df_streets_rabs, self.df_rab_polys, center_type="mean" diff --git a/momepy/tests/test_utils.py b/momepy/tests/test_utils.py index e44f553e..1edc3939 100644 --- a/momepy/tests/test_utils.py +++ b/momepy/tests/test_utils.py @@ -7,9 +7,6 @@ import momepy as mm -# https://github.com/geopandas/geopandas/issues/2282 -GPD_REGR = Version("0.10.2") < Version(gpd.__version__) < Version("0.11") - class TestUtils: def setup_method(self): @@ -120,7 +117,6 @@ def test_gdf_to_nx(self): with pytest.raises(ValueError, match="Directed graphs are not supported"): mm.gdf_to_nx(self.df_streets, approach="dual", directed=True) - @pytest.mark.skipif(GPD_REGR, reason="regression in geopandas") def test_nx_to_gdf(self): nx = mm.gdf_to_nx(self.df_streets) nodes, edges, W = mm.nx_to_gdf(nx, spatial_weights=True) diff --git a/momepy/utils.py b/momepy/utils.py index 515d5765..9a867c9a 100644 --- a/momepy/utils.py +++ b/momepy/utils.py @@ -77,7 +77,7 @@ def _generate_primal(graph, gdf_network, fields, multigraph, oneway_column=None) last = row.geometry.coords[-1] data = list(row)[1:] - attributes = dict(zip(fields, data)) + attributes = dict(zip(fields, data, strict=True)) if multigraph: graph.add_edge(first, last, key=key, **attributes) key += 1 @@ -104,7 +104,7 @@ def _generate_dual(graph, gdf_network, fields, angles, multigraph, angle): for i, row in enumerate(gdf_network.itertuples()): centroid = (row.temp_x_coords, row.temp_y_coords) data = list(row)[1:-2] - attributes = dict(zip(fields, data)) + attributes = dict(zip(fields, data, strict=True)) graph.add_node(centroid, **attributes) if sw.cardinalities[i] > 0: @@ -278,7 +278,7 @@ def gdf_to_nx( def _points_to_gdf(net): """Generate a point gdf from nodes. Helper for ``nx_to_gdf``.""" - node_xy, node_data = zip(*net.nodes(data=True)) + node_xy, node_data = zip(*net.nodes(data=True), strict=True) if isinstance(node_xy[0], int) and "x" in node_data[0]: geometry = [Point(data["x"], data["y"]) for data in node_data] # osmnx graph else: @@ -291,7 +291,7 @@ def _points_to_gdf(net): def _lines_to_gdf(net, points, node_id): """Generate a linestring gdf from edges. Helper for ``nx_to_gdf``.""" - starts, ends, edge_data = zip(*net.edges(data=True)) + starts, ends, edge_data = zip(*net.edges(data=True), strict=True) gdf_edges = gpd.GeoDataFrame(list(edge_data)) if points is True: @@ -329,7 +329,7 @@ def _primal_to_gdf(net, points, lines, spatial_weights, node_id): def _dual_to_gdf(net): """Generate a linestring gdf from a dual network. Helper for ``nx_to_gdf``.""" - starts, edge_data = zip(*net.nodes(data=True)) + starts, edge_data = zip(*net.nodes(data=True), strict=True) gdf_edges = gpd.GeoDataFrame(list(edge_data)) gdf_edges.crs = net.graph["crs"] return gdf_edges diff --git a/momepy/weights.py b/momepy/weights.py index 040e7ef2..3a6dd553 100644 --- a/momepy/weights.py +++ b/momepy/weights.py @@ -138,7 +138,7 @@ def sw_high(k, gdf=None, weights=None, ids=None, contiguity="queen", silent=True w = first_order.sparse wk = sum(w**x for x in range(2, k + 1)) rk, ck = wk.nonzero() - sk = set(zip(rk, ck)) + sk = set(zip(rk, ck, strict=True)) sk = {(i, j) for i, j in sk if i != j} d = {i: [] for i in id_order} for pair in sk: