From e4c5a6b07355151da28375b5b8bd829e01614288 Mon Sep 17 00:00:00 2001 From: Geoff Boeing Date: Thu, 16 Jan 2025 12:20:58 -0800 Subject: [PATCH 1/3] add numpydoc validation to pre-commit --- .pre-commit-config.yaml | 5 +++++ environments/make-env-files.py | 3 ++- osmnx/convert.py | 1 - osmnx/features.py | 4 ++-- osmnx/graph.py | 3 --- osmnx/plot.py | 6 +++--- osmnx/projection.py | 2 +- osmnx/routing.py | 2 +- pyproject.toml | 3 +++ 9 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8d6ae3c2..f27c2792 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,6 +29,11 @@ repos: - id: yamllint args: [--strict, --config-file=./tests/.yamllint.yml] + - repo: https://github.com/numpy/numpydoc + rev: v1.8.0 + hooks: + - id: numpydoc-validation + - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.9.1 hooks: diff --git a/environments/make-env-files.py b/environments/make-env-files.py index 97f83fcd..440ac43f 100644 --- a/environments/make-env-files.py +++ b/environments/make-env-files.py @@ -38,7 +38,7 @@ def make_requirement( Parameters ---------- requirement - A requirement object + A requirement object. pin_exact If True, pin requirement to version rather than using existing specifier. Allows you to convert minimum versions to pinned versions. @@ -49,6 +49,7 @@ def make_requirement( Returns ------- requirement_str + The requirement's name and its specifier(s). """ specifiers = list(requirement.specifier) if pin_exact and len(specifiers) == 1: diff --git a/osmnx/convert.py b/osmnx/convert.py index 0d70e22e..08e7b2ed 100644 --- a/osmnx/convert.py +++ b/osmnx/convert.py @@ -223,7 +223,6 @@ def _validate_node_edge_gdfs( GeoDataFrame of graph nodes uniquely indexed by `osmid`. gdf_edges GeoDataFrame of graph edges uniquely multi-indexed by `(u, v, key)`. - graph_attrs Returns ------- diff --git a/osmnx/features.py b/osmnx/features.py index 626ca08b..38c06923 100644 --- a/osmnx/features.py +++ b/osmnx/features.py @@ -351,10 +351,10 @@ def features_from_xml( ---------- filepath Path to file containing OSM XML data. - tags - Query tags to optionally filter the final GeoDataFrame. polygon Spatial boundaries to optionally filter the final GeoDataFrame. + tags + Query tags to optionally filter the final GeoDataFrame. encoding The OSM XML file's character encoding. diff --git a/osmnx/graph.py b/osmnx/graph.py index 7a9efaee..ea0d920e 100644 --- a/osmnx/graph.py +++ b/osmnx/graph.py @@ -599,9 +599,6 @@ def _create_graph( ---------- response_jsons Iterable of JSON responses from the Overpass API. - retain_all - If True, return the entire graph even if it is not connected. - Otherwise, retain only the largest weakly connected component. bidirectional If True, create bidirectional edges for one-way streets. diff --git a/osmnx/plot.py b/osmnx/plot.py index 9056296a..ccc4a7ee 100644 --- a/osmnx/plot.py +++ b/osmnx/plot.py @@ -325,7 +325,7 @@ def plot_graph_route( Size of the origin and destination nodes. ax If not None, plot on this pre-existing axes instance. - pg_kwargs + **pg_kwargs Keyword arguments to pass to `plot_graph`. Returns @@ -394,7 +394,7 @@ def plot_graph_routes( route_linewidths If float, the one linewidth for all routes. Otherwise, the linewidth for each route. - pgr_kwargs + **pgr_kwargs Keyword arguments to pass to `plot_graph_route`. Returns @@ -487,7 +487,7 @@ def plot_figure_ground( Fallback width, in pixels, for any street type not in `street_widths`. color The color of the streets. - pg_kwargs + **pg_kwargs Keyword arguments to pass to `plot_graph`. Returns diff --git a/osmnx/projection.py b/osmnx/projection.py index 2e946bd0..4d143c5f 100644 --- a/osmnx/projection.py +++ b/osmnx/projection.py @@ -31,7 +31,7 @@ def is_projected(crs: Any) -> bool: # noqa: ANN401 Returns ------- projected - True if `crs` is projected, otherwise False + True if `crs` is projected, otherwise False. """ return bool(gpd.GeoSeries(crs=crs).crs.is_projected) diff --git a/osmnx/routing.py b/osmnx/routing.py index 013e17b1..7643aecc 100644 --- a/osmnx/routing.py +++ b/osmnx/routing.py @@ -316,7 +316,7 @@ def shortest_path( Parameters ---------- G - Input graph, + Input graph. orig Origin node ID(s). dest diff --git a/pyproject.toml b/pyproject.toml index 92742ae2..909c7905 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,6 +69,9 @@ strict = true warn_no_return = true warn_unreachable = true +[tool.numpydoc_validation] +checks = ["all", "ES01", "EX01", "GL08", "PR04", "RT03", "SA01"] + [tool.ruff] cache-dir = "~/.cache/pre-commit/ruff" exclude = ["build/*"] From 5c822592c6b0695ac7b13104558b054786642b0b Mon Sep 17 00:00:00 2001 From: Geoff Boeing Date: Fri, 24 Jan 2025 15:35:58 -0800 Subject: [PATCH 2/3] add return value docstring descriptions --- osmnx/_http.py | 1 + osmnx/_nominatim.py | 2 ++ osmnx/_overpass.py | 2 ++ osmnx/convert.py | 7 ++++++- osmnx/elevation.py | 3 ++- osmnx/features.py | 4 ++++ osmnx/graph.py | 15 +++++++++++++-- osmnx/io.py | 7 ++++++- osmnx/plot.py | 18 ++++++++++++++---- osmnx/routing.py | 1 + osmnx/simplification.py | 3 ++- osmnx/utils.py | 2 ++ osmnx/utils_geo.py | 3 +++ 13 files changed, 58 insertions(+), 10 deletions(-) diff --git a/osmnx/_http.py b/osmnx/_http.py index 3cbcf70b..18c320de 100644 --- a/osmnx/_http.py +++ b/osmnx/_http.py @@ -164,6 +164,7 @@ def _get_http_headers( Returns ------- headers + The updated HTTP headers. """ if user_agent is None: user_agent = settings.http_user_agent diff --git a/osmnx/_nominatim.py b/osmnx/_nominatim.py index 926d26b6..771dba52 100644 --- a/osmnx/_nominatim.py +++ b/osmnx/_nominatim.py @@ -39,6 +39,7 @@ def _download_nominatim_element( Returns ------- response_json + The Nominatim API's response. """ # define the parameters params: OrderedDict[str, int | str] = OrderedDict() @@ -102,6 +103,7 @@ def _nominatim_request( Returns ------- response_json + The Nominatim API's response. """ if request_type not in {"search", "reverse", "lookup"}: # pragma: no cover msg = "Nominatim `request_type` must be 'search', 'reverse', or 'lookup'." diff --git a/osmnx/_overpass.py b/osmnx/_overpass.py index 0b6a7050..9d5a9c6c 100644 --- a/osmnx/_overpass.py +++ b/osmnx/_overpass.py @@ -296,6 +296,7 @@ def _create_overpass_features_query( # noqa: PLR0912 Returns ------- query + The Overpass features query. """ # create overpass settings string overpass_settings = _make_overpass_settings() @@ -450,6 +451,7 @@ def _overpass_request( Returns ------- response_json + The Overpass API's response. """ # resolve url to same IP even if there is server round-robin redirecting _http._config_dns(settings.overpass_url) diff --git a/osmnx/convert.py b/osmnx/convert.py index 08e7b2ed..234ce725 100644 --- a/osmnx/convert.py +++ b/osmnx/convert.py @@ -301,6 +301,7 @@ def graph_from_gdfs( Returns ------- G + The converted MultiDiGraph. """ _validate_node_edge_gdfs(gdf_nodes, gdf_edges) @@ -353,7 +354,8 @@ def to_digraph(G: nx.MultiDiGraph, *, weight: str = "length") -> nx.DiGraph: Returns ------- - G + D + The converted DiGraph. """ # make a copy to not mutate original graph object caller passed in G = G.copy() @@ -396,6 +398,7 @@ def to_undirected(G: nx.MultiDiGraph) -> nx.MultiGraph: Returns ------- Gu + The converted MultiGraph. """ # make a copy to not mutate original graph object caller passed in G = G.copy() @@ -459,6 +462,7 @@ def _is_duplicate_edge(data1: dict[str, Any], data2: dict[str, Any]) -> bool: Returns ------- is_dupe + True if `osmid` and `geometry` are the same, otherwise False. """ is_dupe = False @@ -530,6 +534,7 @@ def _update_edge_keys(G: nx.MultiDiGraph) -> nx.MultiDiGraph: Returns ------- G + Graph with incremented keys where needed. """ # identify all the edges that are duplicates based on a sorted combination # of their origin, destination, and key. that is, edge uv will match edge vu diff --git a/osmnx/elevation.py b/osmnx/elevation.py index 6be8460d..efed1725 100644 --- a/osmnx/elevation.py +++ b/osmnx/elevation.py @@ -288,7 +288,7 @@ def add_node_elevations_google( def _elevation_request(url: str, pause: float) -> dict[str, Any]: """ - Send a HTTP GET request to a Google Maps-style Elevation API. + Send a HTTP GET request to a Google Maps-style elevation API. Parameters ---------- @@ -300,6 +300,7 @@ def _elevation_request(url: str, pause: float) -> dict[str, Any]: Returns ------- response_json + The elevation API's response. """ # check if request already exists in cache cached_response_json = _http._retrieve_from_cache(url) diff --git a/osmnx/features.py b/osmnx/features.py index 38c06923..28d25307 100644 --- a/osmnx/features.py +++ b/osmnx/features.py @@ -444,6 +444,7 @@ def _process_features( Returns ------- features + The features with geometries. """ nodes = [] # all nodes, including ones that just compose ways feature_nodes = [] # nodes that possibly match our query tags @@ -534,6 +535,7 @@ def _build_way_geometry( Returns ------- geometry + The way's geometry. """ # a way is a LineString by default, but if it's a closed way and it's not # tagged area=no, check if any of its tags denote it as a polygon instead @@ -584,6 +586,7 @@ def _build_relation_geometry( Returns ------- geometry + The relation's geometry. """ inner_linestrings = [] outer_linestrings = [] @@ -641,6 +644,7 @@ def _remove_polygon_holes( Returns ------- geometry + The geometry minus inner holes. """ if len(inner_polygons) == 0: # if there are no holes to remove, geom is the union of outer polygons diff --git a/osmnx/graph.py b/osmnx/graph.py index ea0d920e..124f5ad5 100644 --- a/osmnx/graph.py +++ b/osmnx/graph.py @@ -90,6 +90,7 @@ def graph_from_bbox( Returns ------- G + The resulting MultiDiGraph. Notes ----- @@ -180,6 +181,7 @@ def graph_from_point( Returns ------- G + The resulting MultiDiGraph. Notes ----- @@ -224,7 +226,7 @@ def graph_from_address( retain_all: bool = False, truncate_by_edge: bool = False, custom_filter: str | list[str] | None = None, -) -> nx.MultiDiGraph | tuple[nx.MultiDiGraph, tuple[float, float]]: +) -> nx.MultiDiGraph: """ Download and create a graph within some distance of an address. @@ -277,7 +279,8 @@ def graph_from_address( Returns ------- - G or (G, (lat, lon)) + G + The resulting MultiDiGraph. Notes ----- @@ -375,6 +378,7 @@ def graph_from_place( Returns ------- G + The resulting MultiDiGraph. Notes ----- @@ -456,6 +460,7 @@ def graph_from_polygon( Returns ------- G + The resulting MultiDiGraph. Notes ----- @@ -564,6 +569,7 @@ def graph_from_xml( Returns ------- G + The resulting MultiDiGraph. """ # transmogrify file of OSM XML data into JSON response_jsons = [_osm_xml._overpass_json_from_xml(Path(filepath), encoding)] @@ -605,6 +611,7 @@ def _create_graph( Returns ------- G + The resulting MultiDiGraph. """ # each dict's keys are OSM IDs and values are dicts of attributes nodes: dict[int, dict[str, Any]] = {} @@ -669,6 +676,7 @@ def _convert_node(element: dict[str, Any]) -> dict[str, Any]: Returns ------- node + The converted node. """ node = {"y": element["lat"], "x": element["lon"]} if "tags" in element: @@ -690,6 +698,7 @@ def _convert_path(element: dict[str, Any]) -> dict[str, Any]: Returns ------- path + The converted path. """ path = {"osmid": element["id"]} @@ -746,6 +755,7 @@ def _is_path_one_way(attrs: dict[str, Any], bidirectional: bool, oneway_values: Returns ------- is_one_way + True if path allows travel in only one direction, otherwise False. """ # rule 1 if settings.all_oneway: @@ -792,6 +802,7 @@ def _is_path_reversed(attrs: dict[str, Any], reversed_values: set[str]) -> bool: Returns ------- is_reversed + True if nodes' order should be reversed, otherwise False. """ return "oneway" in attrs and attrs["oneway"] in reversed_values diff --git a/osmnx/io.py b/osmnx/io.py index 45c66719..bd8ad056 100644 --- a/osmnx/io.py +++ b/osmnx/io.py @@ -179,6 +179,7 @@ def load_graphml( Returns ------- G + The loaded MultiDiGraph. """ if (filepath is None and graphml_str is None) or ( filepath is not None and graphml_str is not None @@ -310,6 +311,7 @@ def _convert_graph_attr_types(G: nx.MultiDiGraph, dtypes: dict[str, Any]) -> nx. Returns ------- G + The graph with its graph-level attributes' types converted. """ # remove node_default and edge_default metadata keys if they exist G.graph.pop("node_default", None) @@ -335,6 +337,7 @@ def _convert_node_attr_types(G: nx.MultiDiGraph, dtypes: dict[str, Any]) -> nx.M Returns ------- G + The graph with its nodes' attributes' types converted. """ for _, data in G.nodes(data=True): # first, eval stringified lists, dicts, or sets to convert them to objects @@ -365,6 +368,7 @@ def _convert_edge_attr_types(G: nx.MultiDiGraph, dtypes: dict[str, Any]) -> nx.M Returns ------- G + The graph with its edges' attributes' types converted. """ # for each edge in the graph, eval attribute value lists and convert types for _, _, data in G.edges(data=True, keys=False): @@ -411,11 +415,12 @@ def _convert_bool_string(value: bool | str) -> bool: Parameters ---------- value - The string value to convert to bool. + The string to convert to bool. Returns ------- bool_value + The boolean equivalent of the string literal. """ if isinstance(value, bool): return value diff --git a/osmnx/plot.py b/osmnx/plot.py index ccc4a7ee..fdc92ed9 100644 --- a/osmnx/plot.py +++ b/osmnx/plot.py @@ -55,13 +55,13 @@ def get_colors( Parameters ---------- n - How many colors to generate. + How many colors to sample. cmap - Name of the matplotlib colormap from which to choose the colors. + Name of the matplotlib colormap from which to sample the colors. start - Where to start in the colorspace (from 0 to 1). + Where to start sampling from the colorspace (from 0 to 1). stop - Where to end in the colorspace (from 0 to 1). + Where to end sampling from the colorspace (from 0 to 1). alpha If `None`, return colors as HTML-like hex triplet "#rrggbb" RGB strings. If `float`, return as "#rrggbbaa" RGBa strings. @@ -69,6 +69,7 @@ def get_colors( Returns ------- color_list + The sampled colors. """ _verify_mpl() color_gen = (colormaps[cmap](x) for x in np.linspace(start, stop, n)) @@ -237,6 +238,7 @@ def plot_graph( # noqa: PLR0913 Returns ------- fig, ax + The resulting matplotlib figure and axes objects. """ _verify_mpl() max_node_size = max(node_size) if isinstance(node_size, Sequence) else node_size @@ -331,6 +333,7 @@ def plot_graph_route( Returns ------- fig, ax + The resulting matplotlib figure and axes objects. """ _verify_mpl() if ax is None: @@ -400,6 +403,7 @@ def plot_graph_routes( Returns ------- fig, ax + The resulting matplotlib figure and axes objects. """ # make iterables lists (so we're guaranteed to be able to get their sizes) routes = list(routes) @@ -493,6 +497,7 @@ def plot_figure_ground( Returns ------- fig, ax + The resulting matplotlib figure and axes objects. """ _verify_mpl() @@ -628,6 +633,7 @@ def plot_footprints( # noqa: PLR0913 Returns ------- fig, ax + The resulting matplotlib figure and axes objects. """ _verify_mpl() fig, ax = _get_fig_ax(ax=ax, figsize=figsize, bgcolor=bgcolor, polar=False) @@ -731,6 +737,7 @@ def plot_orientation( # noqa: PLR0913 Returns ------- fig, ax + The resulting matplotlib figure and polar axes objects. """ _verify_mpl() @@ -903,6 +910,7 @@ def _save_and_show( Returns ------- fig, ax + The matplotlib figure and axes objects. """ fig.canvas.draw() fig.canvas.flush_events() @@ -964,6 +972,7 @@ def _config_ax(ax: Axes, crs: Any, bbox: tuple[float, float, float, float], padd Returns ------- ax + The configured matplotlib axes object. """ # set the axes view limits to bbox + relative padding left, bottom, right, top = bbox @@ -1035,6 +1044,7 @@ def _get_fig_ax( Returns ------- fig, ax + The resulting matplotlib figure and axes objects. """ if ax is None: if polar: diff --git a/osmnx/routing.py b/osmnx/routing.py index 7643aecc..68ae581d 100644 --- a/osmnx/routing.py +++ b/osmnx/routing.py @@ -198,6 +198,7 @@ def route_to_gdf( Returns ------- gdf_edges + The ordered edges in the path. """ pairs = zip(route[:-1], route[1:]) uvk = ((u, v, min(G[u][v].items(), key=lambda i: i[1][weight])[0]) for u, v in pairs) diff --git a/osmnx/simplification.py b/osmnx/simplification.py index 7de4d062..ca259522 100644 --- a/osmnx/simplification.py +++ b/osmnx/simplification.py @@ -55,7 +55,7 @@ def _is_endpoint( G Input graph. node - The ID of the node. + The ID of the node to check. node_attrs_include Node attribute names for relaxing the strictness of endpoint determination. A node is always an endpoint if it possesses one or @@ -69,6 +69,7 @@ def _is_endpoint( Returns ------- endpoint + True if node is an endpoint, otherwise False. """ neighbors = set(list(G.predecessors(node)) + list(G.successors(node))) n = len(neighbors) diff --git a/osmnx/utils.py b/osmnx/utils.py index 2e4a5a8f..4d7dfa4f 100644 --- a/osmnx/utils.py +++ b/osmnx/utils.py @@ -73,6 +73,7 @@ def ts(style: str = "datetime", template: str | None = None) -> str: Returns ------- timestamp + The current timestamp. """ if template is None: if style == "datetime": @@ -174,6 +175,7 @@ def _get_logger(name: str, filename: str) -> lg.Logger: Returns ------- logger + The logger. """ logger = lg.getLogger(name) diff --git a/osmnx/utils_geo.py b/osmnx/utils_geo.py index f3fb8fc2..8fd13147 100644 --- a/osmnx/utils_geo.py +++ b/osmnx/utils_geo.py @@ -142,6 +142,7 @@ def _consolidate_subdivide_geometry(geom: Polygon | MultiPolygon) -> MultiPolygo Returns ------- geom + The resulting consolidated and subdivided geometry. """ if not isinstance(geom, (Polygon, MultiPolygon)): # pragma: no cover msg = "Geometry must be a shapely Polygon or MultiPolygon." @@ -190,6 +191,7 @@ def _quadrat_cut_geometry(geom: Polygon | MultiPolygon, quadrat_width: float) -> Returns ------- geom + The resulting split-up geometry. """ # min number of dividing lines (3 produces a grid of 4 quadrat squares) min_num = 3 @@ -429,6 +431,7 @@ def bbox_to_poly(bbox: tuple[float, float, float, float]) -> Polygon: Returns ------- polygon + The resulting bounding box polygon. """ left, bottom, right, top = bbox return Polygon([(left, bottom), (right, bottom), (right, top), (left, top)]) From 28e783c414a04b735d55f7cc6114206e4cd1043b Mon Sep 17 00:00:00 2001 From: Geoff Boeing Date: Fri, 24 Jan 2025 15:41:23 -0800 Subject: [PATCH 3/3] update ruff version --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f27c2792..33b72118 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,7 @@ repos: - id: numpydoc-validation - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.1 + rev: v0.9.3 hooks: - id: ruff args: [--fix]