From 52f73d4f3ef3e9aebb9597677fa3b6c9102c241d Mon Sep 17 00:00:00 2001 From: Donatas-L Date: Thu, 30 Apr 2026 10:38:19 +0300 Subject: [PATCH 1/4] Fix proto packaging. Ship bindings as traveltimepy.proto subpackage --- .github/workflows/ci.yml | 2 +- .github/workflows/publish.yml | 28 +++++++++++++++++-- .gitignore | 4 +-- MANIFEST.in | 1 + pyproject.toml | 11 ++------ traveltimepy/async_base_client.py | 4 +-- .../proto}/GeohashFastRequest.proto | 2 +- .../proto}/GeohashFastResponse.proto | 0 .../proto}/RequestsCommon.proto | 0 .../proto}/TimeFilterFastRequest.proto | 2 +- .../proto}/TimeFilterFastResponse.proto | 0 traveltimepy/proto/__init__.py | 0 traveltimepy/requests/geohash_fast_proto.py | 4 +-- traveltimepy/requests/time_filter_proto.py | 4 +-- traveltimepy/sync_base_client.py | 4 +-- 15 files changed, 42 insertions(+), 24 deletions(-) rename {proto => traveltimepy/proto}/GeohashFastRequest.proto (92%) rename {proto => traveltimepy/proto}/GeohashFastResponse.proto (100%) rename {proto => traveltimepy/proto}/RequestsCommon.proto (100%) rename {proto => traveltimepy/proto}/TimeFilterFastRequest.proto (97%) rename {proto => traveltimepy/proto}/TimeFilterFastResponse.proto (100%) create mode 100644 traveltimepy/proto/__init__.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ec37af1..f8c8e1a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,7 @@ jobs: - name: Generate proto files run: | - protoc -I=proto/ --python_out=. proto/*.proto + protoc -I=. --python_out=. traveltimepy/proto/*.proto - name: Test with pytest run: | diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 085aa1f9..cd03ff82 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -27,17 +27,39 @@ jobs: - name: Generate proto files run: | - protoc -I=proto/ --python_out=. proto/*.proto + protoc -I=. --python_out=. traveltimepy/proto/*.proto - name: Install setuptools run: | python -m pip install --upgrade pip pip install build setuptools twine - - name: Build and publish + - name: Build + run: | + python -m build + + - name: Smoke test built wheel + run: | + python -m venv .smoke + WHEEL=$(ls dist/*.whl) + .smoke/bin/pip install --upgrade pip + .smoke/bin/pip install "${WHEEL}[proto]" + .smoke/bin/python -c " + from traveltimepy.proto import ( + RequestsCommon_pb2, + TimeFilterFastRequest_pb2, + TimeFilterFastResponse_pb2, + GeohashFastRequest_pb2, + GeohashFastResponse_pb2, + ) + from traveltimepy.async_base_client import PROTOBUF_AVAILABLE as async_ok + from traveltimepy.sync_base_client import PROTOBUF_AVAILABLE as sync_ok + assert async_ok and sync_ok, 'PROTOBUF_AVAILABLE should be True with [proto] extra' + " + + - name: Publish env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python -m build twine upload dist/* diff --git a/.gitignore b/.gitignore index a95d15c3..aec5fbbd 100644 --- a/.gitignore +++ b/.gitignore @@ -178,5 +178,5 @@ dmypy.json # Cython debug symbols cython_debug/ -# Proto -*_pb2.py +# Proto (generated by protoc into traveltimepy/proto/ during build) +traveltimepy/proto/*_pb2.py diff --git a/MANIFEST.in b/MANIFEST.in index bb3ec5f0..a44ff1ed 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,2 @@ include README.md +recursive-include traveltimepy/proto *.proto diff --git a/pyproject.toml b/pyproject.toml index 7cdbb992..72c42595 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,14 +54,9 @@ test = [ [tool.setuptools] zip-safe = false include-package-data = true -py-modules = [ - "RequestsCommon_pb2", - "TimeFilterFastRequest_pb2", - "TimeFilterFastResponse_pb2", - "GeohashFastRequest_pb2", - "GeohashFastResponse_pb2", -] -packages = { find = {} } + +[tool.setuptools.packages.find] +include = ["traveltimepy*"] [tool.setuptools_scm] diff --git a/traveltimepy/async_base_client.py b/traveltimepy/async_base_client.py index 7b6f649c..f31c7f39 100644 --- a/traveltimepy/async_base_client.py +++ b/traveltimepy/async_base_client.py @@ -14,8 +14,8 @@ ) try: - import TimeFilterFastResponse_pb2 # type: ignore - import GeohashFastResponse_pb2 # type: ignore + from traveltimepy.proto import TimeFilterFastResponse_pb2 # type: ignore + from traveltimepy.proto import GeohashFastResponse_pb2 # type: ignore PROTOBUF_AVAILABLE = True except ImportError: diff --git a/proto/GeohashFastRequest.proto b/traveltimepy/proto/GeohashFastRequest.proto similarity index 92% rename from proto/GeohashFastRequest.proto rename to traveltimepy/proto/GeohashFastRequest.proto index c254a22d..305acba2 100644 --- a/proto/GeohashFastRequest.proto +++ b/traveltimepy/proto/GeohashFastRequest.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package com.igeolise.traveltime.rabbitmq.requests; -import "RequestsCommon.proto"; +import "traveltimepy/proto/RequestsCommon.proto"; message GeohashFastRequest { message OneToMany { diff --git a/proto/GeohashFastResponse.proto b/traveltimepy/proto/GeohashFastResponse.proto similarity index 100% rename from proto/GeohashFastResponse.proto rename to traveltimepy/proto/GeohashFastResponse.proto diff --git a/proto/RequestsCommon.proto b/traveltimepy/proto/RequestsCommon.proto similarity index 100% rename from proto/RequestsCommon.proto rename to traveltimepy/proto/RequestsCommon.proto diff --git a/proto/TimeFilterFastRequest.proto b/traveltimepy/proto/TimeFilterFastRequest.proto similarity index 97% rename from proto/TimeFilterFastRequest.proto rename to traveltimepy/proto/TimeFilterFastRequest.proto index 7056021f..d50031a0 100644 --- a/proto/TimeFilterFastRequest.proto +++ b/traveltimepy/proto/TimeFilterFastRequest.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package com.igeolise.traveltime.rabbitmq.requests; -import "RequestsCommon.proto"; +import "traveltimepy/proto/RequestsCommon.proto"; message TimeFilterFastRequest { enum Property { diff --git a/proto/TimeFilterFastResponse.proto b/traveltimepy/proto/TimeFilterFastResponse.proto similarity index 100% rename from proto/TimeFilterFastResponse.proto rename to traveltimepy/proto/TimeFilterFastResponse.proto diff --git a/traveltimepy/proto/__init__.py b/traveltimepy/proto/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/traveltimepy/requests/geohash_fast_proto.py b/traveltimepy/requests/geohash_fast_proto.py index 12071bc8..ef9225c1 100644 --- a/traveltimepy/requests/geohash_fast_proto.py +++ b/traveltimepy/requests/geohash_fast_proto.py @@ -2,8 +2,8 @@ from typing import List, Union try: - import RequestsCommon_pb2 # type: ignore - import GeohashFastRequest_pb2 # type: ignore + from traveltimepy.proto import RequestsCommon_pb2 # type: ignore + from traveltimepy.proto import GeohashFastRequest_pb2 # type: ignore PROTOBUF_AVAILABLE = True except ImportError: diff --git a/traveltimepy/requests/time_filter_proto.py b/traveltimepy/requests/time_filter_proto.py index 2ee1bb1d..f632251b 100644 --- a/traveltimepy/requests/time_filter_proto.py +++ b/traveltimepy/requests/time_filter_proto.py @@ -4,8 +4,8 @@ from typing import ClassVar, Optional, List, Union try: - import RequestsCommon_pb2 # type: ignore - import TimeFilterFastRequest_pb2 # type: ignore + from traveltimepy.proto import RequestsCommon_pb2 # type: ignore + from traveltimepy.proto import TimeFilterFastRequest_pb2 # type: ignore PROTOBUF_AVAILABLE = True except ImportError: diff --git a/traveltimepy/sync_base_client.py b/traveltimepy/sync_base_client.py index f0453c72..3f44d243 100644 --- a/traveltimepy/sync_base_client.py +++ b/traveltimepy/sync_base_client.py @@ -15,8 +15,8 @@ ) try: - import TimeFilterFastResponse_pb2 # type: ignore - import GeohashFastResponse_pb2 # type: ignore + from traveltimepy.proto import TimeFilterFastResponse_pb2 # type: ignore + from traveltimepy.proto import GeohashFastResponse_pb2 # type: ignore PROTOBUF_AVAILABLE = True except ImportError: From 09038bc4b3df56bb04db1049005ddaebe4d32c8f Mon Sep 17 00:00:00 2001 From: Donatas-L Date: Thu, 30 Apr 2026 11:04:53 +0300 Subject: [PATCH 2/4] Harden release smoke tes --- .github/workflows/publish.yml | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cd03ff82..d3277143 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,4 +1,4 @@ -# This workflows will upload a Python Package using Twine when a release is created +# This workflow will upload a Python Package using Twine when a release is created # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries name: Build & Upload package @@ -23,7 +23,7 @@ jobs: - name: Set up protoc uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 with: - version: '3.x' + version: '25.x' - name: Generate proto files run: | @@ -39,12 +39,16 @@ jobs: python -m build - name: Smoke test built wheel + # Runs from /tmp so the repo source tree isn't picked up via sys.path[0] + working-directory: /tmp run: | - python -m venv .smoke - WHEEL=$(ls dist/*.whl) - .smoke/bin/pip install --upgrade pip - .smoke/bin/pip install "${WHEEL}[proto]" - .smoke/bin/python -c " + WHEEL="$(ls "$GITHUB_WORKSPACE"/dist/*.whl)" + + # With [proto] extra: protobuf modules import, PROTOBUF_AVAILABLE is True. + python -m venv smoke + smoke/bin/pip install --upgrade pip + smoke/bin/pip install "${WHEEL}[proto]" + smoke/bin/python -c " from traveltimepy.proto import ( RequestsCommon_pb2, TimeFilterFastRequest_pb2, @@ -57,6 +61,16 @@ jobs: assert async_ok and sync_ok, 'PROTOBUF_AVAILABLE should be True with [proto] extra' " + # Without extras: SDK still imports, PROTOBUF_AVAILABLE is False. + python -m venv smoke-bare + smoke-bare/bin/pip install --upgrade pip + smoke-bare/bin/pip install "${WHEEL}" + smoke-bare/bin/python -c " + from traveltimepy.async_base_client import PROTOBUF_AVAILABLE as async_ok + from traveltimepy.sync_base_client import PROTOBUF_AVAILABLE as sync_ok + assert not async_ok and not sync_ok, 'PROTOBUF_AVAILABLE should be False without [proto] extra' + " + - name: Publish env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} From 1c5bb19cb42f481876f31edd2971a6fb50222f66 Mon Sep 17 00:00:00 2001 From: Donatas-L Date: Thu, 30 Apr 2026 11:48:54 +0300 Subject: [PATCH 3/4] fmt --- .github/workflows/publish.yml | 4 +--- examples/time_filter_fast_matrix.py | 1 - examples/time_filter_matrix.py | 1 - traveltimepy/async_client.py | 8 -------- traveltimepy/client.py | 8 -------- traveltimepy/requests/common.py | 5 +++-- 6 files changed, 4 insertions(+), 23 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d3277143..8e1de3a2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -29,7 +29,7 @@ jobs: run: | protoc -I=. --python_out=. traveltimepy/proto/*.proto - - name: Install setuptools + - name: Install build tools run: | python -m pip install --upgrade pip pip install build setuptools twine @@ -44,7 +44,6 @@ jobs: run: | WHEEL="$(ls "$GITHUB_WORKSPACE"/dist/*.whl)" - # With [proto] extra: protobuf modules import, PROTOBUF_AVAILABLE is True. python -m venv smoke smoke/bin/pip install --upgrade pip smoke/bin/pip install "${WHEEL}[proto]" @@ -61,7 +60,6 @@ jobs: assert async_ok and sync_ok, 'PROTOBUF_AVAILABLE should be True with [proto] extra' " - # Without extras: SDK still imports, PROTOBUF_AVAILABLE is False. python -m venv smoke-bare smoke-bare/bin/pip install --upgrade pip smoke-bare/bin/pip install "${WHEEL}" diff --git a/examples/time_filter_fast_matrix.py b/examples/time_filter_fast_matrix.py index c746ce47..9b68f540 100644 --- a/examples/time_filter_fast_matrix.py +++ b/examples/time_filter_fast_matrix.py @@ -167,7 +167,6 @@ def main(): "Error: Please set TRAVELTIME_APP_ID and TRAVELTIME_API_KEY environment variables" ) exit(1) - """Generate a specified amount of random locations around a point.""" MATRIX_SIZE = 3 locations = generate_locations( diff --git a/examples/time_filter_matrix.py b/examples/time_filter_matrix.py index 25cf3b38..789fe02f 100644 --- a/examples/time_filter_matrix.py +++ b/examples/time_filter_matrix.py @@ -159,7 +159,6 @@ def main(): "Error: Please set TRAVELTIME_APP_ID and TRAVELTIME_API_KEY environment variables" ) exit(1) - """Generate a specified amount of random locations around a point.""" MATRIX_SIZE = 3 locations = generate_locations( diff --git a/traveltimepy/async_client.py b/traveltimepy/async_client.py index fbe48d83..2b0977e0 100644 --- a/traveltimepy/async_client.py +++ b/traveltimepy/async_client.py @@ -176,7 +176,6 @@ async def time_filter_fast( TimeFilterFastResponse: Travel times and distances for reachable locations based on requested properties. """ - return await self._api_call_post( TimeFilterFastResponse, "time-filter/fast", @@ -309,7 +308,6 @@ async def geocoding( FeatureCollection containing geocoding results with coordinates, addresses, confidence scores, and location metadata. """ - return await self._api_call_get( FeatureCollection, "geocoding/search", @@ -349,7 +347,6 @@ async def reverse_geocoding( 400 Bad Request: If coordinates are far from land (e.g., in ocean). Reverse search is only supported for points on land. """ - return await self._api_call_get( FeatureCollection, "geocoding/reverse", @@ -701,7 +698,6 @@ async def geohash( GeoHashResponse containing travel time statistics for each geohash cell within the reachable area. """ - return await self._api_call_post( GeoHashResponse, "geohash", @@ -778,7 +774,6 @@ async def postcodes( PostcodesResponse: Travel statistics for reachable postcodes including travel times and distances based on requested properties. """ - return await self._api_call_post( PostcodesResponse, "time-filter/postcodes", @@ -807,7 +802,6 @@ async def postcode_districts( PostcodesDistrictsResponse: Statistics for postcode districts including travel times and coverage percentages. """ - return await self._api_call_post( PostcodesDistrictsResponse, "time-filter/postcode-districts", @@ -836,7 +830,6 @@ async def postcode_sectors( PostcodesSectorsResponse: Statistics for postcode sectors including travel times and coverage percentages. """ - return await self._api_call_post( PostcodesSectorsResponse, "time-filter/postcode-sectors", @@ -908,7 +901,6 @@ async def distance_map( TimeMapResponse containing polygon shapes for each search operation, with results sorted lexicographically by search_id. """ - return await self._api_call_post( TimeMapResponse, "distance-map", diff --git a/traveltimepy/client.py b/traveltimepy/client.py index 9471f446..a3d4bfa4 100644 --- a/traveltimepy/client.py +++ b/traveltimepy/client.py @@ -172,7 +172,6 @@ def time_filter_fast( TimeFilterFastResponse: Travel times and distances for reachable locations based on requested properties. """ - return self._api_call_post( TimeFilterFastResponse, "time-filter/fast", @@ -305,7 +304,6 @@ def geocoding( FeatureCollection containing geocoding results with coordinates, addresses, confidence scores, and location metadata. """ - return self._api_call_get( FeatureCollection, "geocoding/search", @@ -345,7 +343,6 @@ def reverse_geocoding( 400 Bad Request: If coordinates are far from land (e.g., in ocean). Reverse search is only supported for points on land. """ - return self._api_call_get( FeatureCollection, "geocoding/reverse", @@ -697,7 +694,6 @@ def geohash( GeoHashResponse containing travel time statistics for each geohash cell within the reachable area. """ - return self._api_call_post( GeoHashResponse, "geohash", @@ -774,7 +770,6 @@ def postcodes( PostcodesResponse: Travel statistics for reachable postcodes including travel times and distances based on requested properties. """ - return self._api_call_post( PostcodesResponse, "time-filter/postcodes", @@ -803,7 +798,6 @@ def postcode_districts( PostcodesDistrictsResponse: Statistics for postcode districts including travel times and coverage percentages. """ - return self._api_call_post( PostcodesDistrictsResponse, "time-filter/postcode-districts", @@ -832,7 +826,6 @@ def postcode_sectors( PostcodesSectorsResponse: Statistics for postcode sectors including travel times and coverage percentages. """ - return self._api_call_post( PostcodesSectorsResponse, "time-filter/postcode-sectors", @@ -904,7 +897,6 @@ def distance_map( TimeMapResponse containing polygon shapes for each search operation, with results sorted lexicographically by search_id. """ - return self._api_call_post( TimeMapResponse, "distance-map", diff --git a/traveltimepy/requests/common.py b/traveltimepy/requests/common.py index 5abe6d3c..3c49930b 100644 --- a/traveltimepy/requests/common.py +++ b/traveltimepy/requests/common.py @@ -161,8 +161,9 @@ def to_str(self): class Property(str, Enum): - """Defines what data should be returned in API responses. Different endpoints - support different combinations of these properties. + """Defines what data should be returned in API responses. + + Different endpoints support different combinations of these properties. Attributes: TRAVEL_TIME: Journey time in seconds From 5294b2a45e69b87a2038812bc48566d5f2eebce3 Mon Sep 17 00:00:00 2001 From: Donatas-L Date: Thu, 30 Apr 2026 12:07:33 +0300 Subject: [PATCH 4/4] fmt --- traveltimepy/requests/common.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/traveltimepy/requests/common.py b/traveltimepy/requests/common.py index 3c49930b..919e14ed 100644 --- a/traveltimepy/requests/common.py +++ b/traveltimepy/requests/common.py @@ -284,17 +284,16 @@ class FullRange(BaseModel): Limited to 5 results. Must be greater than 0. """ - width: int = Field(gt=0, le=43200) - """Defines the width of the time range window in seconds. - - Behavior varies based on whether searching by departure or arrival time: - - For departure time: Window extends forward (e.g., 9:00am with 1-hour width - includes journeys departing 9:00am-10:00am) - - For arrival time: Window extends backward (e.g., 9:00am with 1-hour width - includes journeys arriving 8:00am-9:00am) - - Must be greater than 0. Maximum allowed value: 43,200 seconds (12 hours). - """ + width: int = Field( + gt=0, + le=43200, + description=( + "Width of the time range window in seconds. For departure time the " + "window extends forward (e.g. 9:00am with 1-hour width includes " + "journeys departing 9:00am-10:00am); for arrival time it extends " + "backward. Maximum 43,200 seconds (12 hours)." + ), + ) class Range(BaseModel):