diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0d71c7..d9fdca5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: CI +name: Tests # Continuous Integration on: pull_request: @@ -21,12 +21,17 @@ jobs: test: name: Python ${{ matrix.python-version }} runs-on: ubuntu-latest + continue-on-error: ${{ endsWith(matrix.python-version, '-dev') }} strategy: fail-fast: false matrix: python-version: + - "3.10" - "3.11" - "3.12" + - "3.13" + - "3.14" +# - "3.15-dev" steps: - name: Check out repository @@ -36,6 +41,7 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + allow-prereleases: ${{ endsWith(matrix.python-version, '-dev') }} cache: pip - name: Install package and test dependencies diff --git a/.github/workflows/release-management.yml b/.github/workflows/release-management.yml index a8aa6e8..fb2f0c3 100644 --- a/.github/workflows/release-management.yml +++ b/.github/workflows/release-management.yml @@ -39,7 +39,7 @@ jobs: fi version="${tag_name#v}" - if [[ "$version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)([-+].*)?$ ]]; then + if [[ "$version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)((a|b|rc)[0-9]+|[-+].*)?$ ]]; then patch_segment="${BASH_REMATCH[3]}" else echo "Unable to parse semantic version from $tag_name." @@ -151,8 +151,14 @@ jobs: for line in lines[start_index + 1 :]: stripped = line.strip() next_heading = re.match(r"^(#{1,6})\s+", stripped) - if next_heading and len(next_heading.group(1)) <= heading_level: + + # Version sections in this changelog always use ## or ###. + # Keep #### subsections like "Issues Closed" and "Deprecations" + # within the matched release notes, but stop at the next version + # heading so a minor release does not absorb later patch releases. + if next_heading and len(next_heading.group(1)) in {2, 3}: break + body_lines.append(line) body = "\n".join(body_lines).strip() diff --git a/.github/workflows/update_version.yml b/.github/workflows/update_version.yml index b2c1d6d..17f783c 100644 --- a/.github/workflows/update_version.yml +++ b/.github/workflows/update_version.yml @@ -41,25 +41,19 @@ jobs: echo "__version__ = \"${version}\"" > src/osmh3nx/__version__.py python - <<'PY' import pathlib - import re - - version = pathlib.Path("src/osmh3nx/__version__.py").read_text(encoding="utf-8") - match = re.search(r'__version__\s*=\s*"([^"]+)"', version) - if not match: - raise SystemExit("Could not read version from src/osmh3nx/__version__.py") - resolved_version = match.group(1) init_path = pathlib.Path("src/osmh3nx/__init__.py") init_text = init_path.read_text(encoding="utf-8") - updated_text, count = re.subn( - r'__version__\s*=\s*"[^"]+"', - f'__version__ = "{resolved_version}"', - init_text, - count=1, - ) - if count != 1: - raise SystemExit("Could not update __version__ assignment in src/osmh3nx/__init__.py") - init_path.write_text(updated_text, encoding="utf-8") + version_import_line = "from .__version__ import __version__" + if version_import_line not in init_text: + lines = init_text.splitlines() + insert_at = 0 + if lines and lines[0].startswith("from __future__ import annotations"): + insert_at = 1 + while insert_at < len(lines) and not lines[insert_at].strip(): + insert_at += 1 + lines.insert(insert_at, version_import_line) + init_path.write_text("\n".join(lines) + "\n", encoding="utf-8") PY - name: Prepare version for badge diff --git a/README.md b/README.md index 78c08dc..0f8eb6c 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@ Hexagonal [H3](https://h3geo.org/) routing, drivesheds, and scalable GIS network [//]: # (Embedding badges: https://naereen.github.io/badges/) [![Version](https://img.shields.io/badge/version-0.1.0b1-D12828.svg)](https://github.com/ccaoa/osmh3nx) -[![Python versions](https://img.shields.io/badge/python-3.11%20%7C%203.12-E6BD29.svg)](https://www.python.org/) +[![Python versions](https://img.shields.io/badge/python-3.10%E2%80%933.14-E6BD29.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-BSD%203--Clause-0B6E4F.svg)](LICENSE) -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://black.readthedocs.io/) [![PyPI Latest Release](https://img.shields.io/pypi/v/osmh3nx.svg)](https://pypi.org/project/osmh3nx/) [![PyPI Downloads](https://img.shields.io/pypi/dm/osmh3nx.svg?label=PyPI%20downloads)](https://pypi.org/project/osmh3nx/) - +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://black.readthedocs.io/) +[![Tests](https://github.com/ccaoa/osmh3nx/actions/workflows/ci.yml/badge.svg)](https://github.com/ccaoa/osmh3nx/actions/workflows/ci.yml) `osmh3nx` is a Python package for building reusable H3-based transportation networks from OpenStreetMap drive graphs, then using those networks for routing, nearest-target assignment, diff --git a/pyproject.toml b/pyproject.toml index bb36772..74063a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ description = "Hexagonal H3 routing, drivesheds, and scalable GIS network analys readme = "README.md" license = "BSD-3-Clause" license-files = ["LICENSE"] -requires-python = ">=3.11" +requires-python = ">=3.10" authors = [ { name = "Alex Cooper" }, { email = "jacooper1317@gmail.com" } @@ -54,6 +54,7 @@ development = [ "black", "pip-tools", "pytest", + "tomli; python_version < '3.11'", ] typecheck = [ "pandas-stubs", diff --git a/requirements.txt b/requirements.txt index c746de7..9685991 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,38 +1,42 @@ black==26.3.1 -build==1.4.2 -certifi==2026.2.25 +build==1.5.0 +certifi==2026.4.22 charset-normalizer==3.4.7 -click==8.3.1 +click==8.3.3 colorama==0.4.6 geopandas==1.1.3 h3==4.4.2 -idna==3.11 +idna==3.14 +iniconfig==2.3.0 joblib==1.5.3 mypy_extensions==1.1.0 networkx==3.6.1 numpy==2.4.4 osmnx==2.1.0 -packaging==26.0 -pandas==3.0.2 +packaging==26.2 +pandas==3.0.3 pandas-stubs==3.0.0.260204 -pathspec==1.0.4 +pathspec==1.1.1 pip-tools==7.5.3 -platformdirs==4.9.4 +platformdirs==4.9.6 +pluggy==1.6.0 +Pygments==2.20.0 pyogrio==0.12.1 pyproj==3.7.2 pyproject_hooks==1.2.0 +pytest==9.0.3 python-dateutil==2.9.0.post0 pytokens==0.4.1 -requests==2.33.1 +requests==2.34.0 scikit-learn==1.8.0 scipy==1.17.1 setuptools==82.0.1 shapely==2.1.2 six==1.17.0 threadpoolctl==3.6.0 -types-geopandas==1.1.3.20260402 -types-networkx==3.6.1.20260402 -types-shapely==2.1.0.20260402 -tzdata==2026.1 -urllib3==2.6.3 -wheel==0.46.3 +types-geopandas==1.1.3.20260508 +types-networkx==3.6.1.20260508 +types-shapely==2.1.0.20260508 +tzdata==2026.2 +urllib3==2.7.0 +wheel==0.47.0 diff --git a/src/osmh3nx/__init__.py b/src/osmh3nx/__init__.py index 0a0b0d8..3985aa8 100644 --- a/src/osmh3nx/__init__.py +++ b/src/osmh3nx/__init__.py @@ -1,5 +1,6 @@ from __future__ import annotations +from .__version__ import __version__ from .calibrate import ( DEFAULT_PROFILE_NAME, CalibrationProfile, @@ -33,6 +34,7 @@ from .spatial import create_buffered_convex_hull, create_convex_hull __all__ = [ + "__version__", "DEFAULT_H3_RES", "DEFAULT_H3_WEIGHT_ATTR", "DEFAULT_PROFILE_NAME", @@ -60,5 +62,3 @@ "select_driveshed_cells_from_lookup", "write_driveshed_result_to_gpkg", ] - -__version__ = "0.1.0b1" diff --git a/tests/test_imports.py b/tests/test_imports.py index a3f0017..6e14a64 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -1,7 +1,11 @@ from __future__ import annotations import pathlib -import tomllib + +try: + import tomllib +except ModuleNotFoundError: + import tomli as tomllib import osmh3nx from osmh3nx import __version__ as package_init_version