From 572eb4169040d7e5129b1d4655aca40cb6602c44 Mon Sep 17 00:00:00 2001 From: Andreas Gemsa Date: Wed, 20 May 2026 20:30:02 +0200 Subject: [PATCH 1/2] Clean up dependency and tooling configuration - Consolidate dev dependencies into a single [dependency-groups] dev group (pytest, ruff, mypy). Previously pytest sat in [project.optional-dependencies] while ruff/black were in [dependency-groups] -- two groups both named "dev" with split contents. mypy is added since CI relies on it. - Declare networkx as a proper optional dependency ([project.optional-dependencies] networkx) so it can be installed via OsmToRoadGraph[networkx] instead of a manual side install. - Remove the duplicate "SIM" entry from the ruff lint select list. - Drop black in favour of ruff's built-in formatter: remove [tool.black] and add [tool.ruff] with line-length = 120 and target-version = "py313" (the old black target-version py311 also contradicted requires-python >= 3.13). CI now runs `ruff format --check` instead of `black --check`. One f-string whitespace normalization in algorithms.py results from the formatter switch. - README: document networkx as an optional dependency installable via the OsmToRoadGraph[networkx] extra. Note: CI still lints with flake8; switching it to `ruff check` is left out because ruff currently reports pre-existing findings that would need to be resolved first. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/build.yml | 6 +++--- README.md | 2 +- graph/algorithms.py | 2 +- pyproject.toml | 22 ++++++++++++---------- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 38ac936..29da303 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,15 +17,15 @@ jobs: run: | python -m pip install --upgrade pip pip install networkx - pip install black codecov flake8 mypy pytest pytest-cov + pip install ruff codecov flake8 mypy pytest pytest-cov - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. flake8 . --count --exit-zero --max-complexity=10 --max-line-length=160 --statistics - - name: Install and run Black - run: black --check . + - name: Check formatting with ruff + run: ruff format --check . - name: Typechecking with mypy run: mypy . --ignore-missing-imports - name: Test with pytest diff --git a/README.md b/README.md index ffb151f..9950f30 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ As an additional feature, and to make interaction easier, since version 0.5 OsmT - Python 3.13+/PyPy - An OSM XML file -- [Optional: [networkx](https://networkx.github.io/) as dependency: `pip3 install networkx`] +- Optional: [networkx](https://networkx.github.io/) — only required for the `--networkx` JSON output. Install it via the optional dependency: `pip3 install OsmToRoadGraph[networkx]` (or directly: `pip3 install networkx`). ### Older Versions diff --git a/graph/algorithms.py b/graph/algorithms.py index ea5fe85..755d6c2 100644 --- a/graph/algorithms.py +++ b/graph/algorithms.py @@ -35,7 +35,7 @@ def computeLCC(graph): # determine largest connected components lcc = max(found_nodes, key=len) - print(f"\t LCC contains {len(lcc)} nodes (removed { len(graph.vertices) - len(lcc)} nodes)") + print(f"\t LCC contains {len(lcc)} nodes (removed {len(graph.vertices) - len(lcc)} nodes)") return lcc diff --git a/pyproject.toml b/pyproject.toml index 537a562..89f08a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,18 +6,20 @@ requires-python = ">=3.13" dependencies = [] [project.optional-dependencies] -dev = ["pytest"] -[tool.black] -line-length = 120 -target-version = ['py311'] - -[tool.ruff.lint] -select = ["I", "F", "SIM", "E", "A", "ARG", "B", "C4", "SIM", "TC", "RET", "TID", "Q"] -ignore = ["E501"] -fixable = ["ALL"] +networkx = ["networkx"] [dependency-groups] dev = [ - "black>=25.1.0", + "mypy", + "pytest", "ruff>=0.12.5", ] + +[tool.ruff] +line-length = 120 +target-version = "py313" + +[tool.ruff.lint] +select = ["I", "F", "SIM", "E", "A", "ARG", "B", "C4", "TC", "RET", "TID", "Q"] +ignore = ["E501"] +fixable = ["ALL"] From 49de0edbbdbabdc136dd5ca318e6c9881a217ed8 Mon Sep 17 00:00:00 2001 From: Andreas Gemsa Date: Thu, 21 May 2026 19:25:42 +0200 Subject: [PATCH 2/2] Switch CI linting to ruff and modernize build.yml CI now lints with `ruff check` instead of flake8, so the [tool.ruff.lint] configuration in pyproject.toml is actually enforced. flake8 is dropped from the workflow dependencies. Also bumped the deprecated action versions: actions/checkout@v1 -> v4 and actions/setup-python@v1 -> v5 (both v1 releases run on long-EOL Node). Resolved the 5 pre-existing lint findings that ruff reports but flake8 did not, so the build stays green: - way_parser_helper.is_way_acceptable: return the condition directly (SIM103) - xml_handler indoor branch: collapse the nested if into the elif (SIM102) - xml_handler PercentageFile: SIM115 silenced with a noqa + rationale; the handle is intentionally owned for the wrapper's lifetime - shortest-distances-drawing example: two if/else blocks turned into ternary expressions (SIM108) Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/build.yml | 16 ++++++---------- .../shortest-distances-drawing.py | 10 ++-------- osm/way_parser_helper.py | 5 +---- osm/xml_handler.py | 15 ++++++++------- 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 29da303..240c7b1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,22 +8,18 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Set up Python 3.13 - uses: actions/setup-python@v1 + uses: actions/setup-python@v5 with: - python-version: 3.13 + python-version: "3.13" - name: Install dependencies run: | python -m pip install --upgrade pip pip install networkx - pip install ruff codecov flake8 mypy pytest pytest-cov - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=160 --statistics + pip install ruff codecov mypy pytest pytest-cov + - name: Lint with ruff + run: ruff check . - name: Check formatting with ruff run: ruff format --check . - name: Typechecking with mypy diff --git a/examples/shortest-distances-drawing/shortest-distances-drawing.py b/examples/shortest-distances-drawing/shortest-distances-drawing.py index 5cadfb2..50379ee 100644 --- a/examples/shortest-distances-drawing/shortest-distances-drawing.py +++ b/examples/shortest-distances-drawing/shortest-distances-drawing.py @@ -98,10 +98,7 @@ def draw_graph_on_map(G, lengths, output_filename, width=1600, height=1200): # determine color distance = line_data[2] - if distance < float("inf"): - luminosity = round(float(distance) / float(max_distance) * 100.0, 0) - else: - luminosity = 100.0 + luminosity = round(float(distance) / float(max_distance) * 100.0, 0) if distance < float("inf") else 100.0 color = get_color(luminosity) @@ -163,10 +160,7 @@ def edge_length(_u, _v, data): sys.exit(-1) G = load_graph(args.in_filename) - if args.center: - start_node = find_approximate_central_node(G) - else: - start_node = random.choice(list(G)) + start_node = find_approximate_central_node(G) if args.center else random.choice(list(G)) metric = None if args.metric == "travel-time": diff --git a/osm/way_parser_helper.py b/osm/way_parser_helper.py index c0096b9..124a58f 100644 --- a/osm/way_parser_helper.py +++ b/osm/way_parser_helper.py @@ -17,10 +17,7 @@ def is_way_acceptable(self, way: OSMWay): if way.area == "yes": return False - if way.highway not in self.config.accepted_highways[self.config.network_type]: - return False - - return True + return way.highway in self.config.accepted_highways[self.config.network_type] def parse_direction(self, way): if way.direction == self.ONEWAY_STR: diff --git a/osm/xml_handler.py b/osm/xml_handler.py index b84da5e..2fcbd55 100644 --- a/osm/xml_handler.py +++ b/osm/xml_handler.py @@ -14,7 +14,9 @@ class PercentageFile: def __init__(self, filename: str) -> None: self.size = os.stat(filename)[6] self.delivered = 0 - self.f = open(filename, encoding="utf-8") + # the handle is owned for the lifetime of this wrapper and released + # in close(); a context manager does not fit this streaming use + self.f = open(filename, encoding="utf-8") # noqa: SIM115 self.percentages = [1000] + [100 - 10 * x for x in range(0, 11)] def read(self, size: Optional[int] = None) -> str: @@ -93,12 +95,11 @@ def startElement(self, name: str, attrs: AttributesImpl) -> None: elif attrs["k"] == "junction": if attrs["v"] == "roundabout": self.current_way.direction = "oneway" - elif attrs["k"] == "indoor": - # this is not an ideal solution since it sets the pedestrian flag irrespective of the real value in osm data - # but aims to cover the simple indoor tagging approach: https://wiki.openstreetmap.org/wiki/Simple_Indoor_Tagging - # more info: https://help.openstreetmap.org/questions/61025/pragmatic-single-level-indoor-paths - if attrs["v"] == "corridor": - self.current_way.highway = "pedestrian_indoor" + # this is not an ideal solution since it sets the pedestrian flag irrespective of the real value in osm data + # but aims to cover the simple indoor tagging approach: https://wiki.openstreetmap.org/wiki/Simple_Indoor_Tagging + # more info: https://help.openstreetmap.org/questions/61025/pragmatic-single-level-indoor-paths + elif attrs["k"] == "indoor" and attrs["v"] == "corridor": + self.current_way.highway = "pedestrian_indoor" except Exception as e: print(f"Error while parsing: {e}")