diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ec37af..f8c8e1a 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 085aa1f..8e1de3a 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,21 +23,55 @@ 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: | - protoc -I=proto/ --python_out=. proto/*.proto + 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 - - name: Build and publish + - name: Build + run: | + 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: | + WHEEL="$(ls "$GITHUB_WORKSPACE"/dist/*.whl)" + + 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, + 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' + " + + 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 }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python -m build twine upload dist/* diff --git a/.gitignore b/.gitignore index a95d15c..aec5fbb 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 bb3ec5f..a44ff1e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,2 @@ include README.md +recursive-include traveltimepy/proto *.proto diff --git a/examples/time_filter_fast_matrix.py b/examples/time_filter_fast_matrix.py index c746ce4..9b68f54 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 25cf3b3..789fe02 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/pyproject.toml b/pyproject.toml index 7cdbb99..72c4259 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 7b6f649..f31c7f3 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/traveltimepy/async_client.py b/traveltimepy/async_client.py index fbe48d8..2b0977e 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 9471f44..a3d4bfa 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/proto/GeohashFastRequest.proto b/traveltimepy/proto/GeohashFastRequest.proto similarity index 92% rename from proto/GeohashFastRequest.proto rename to traveltimepy/proto/GeohashFastRequest.proto index c254a22..305acba 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 7056021..d50031a 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 0000000..e69de29 diff --git a/traveltimepy/requests/common.py b/traveltimepy/requests/common.py index 5abe6d3..919e14e 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 @@ -283,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): diff --git a/traveltimepy/requests/geohash_fast_proto.py b/traveltimepy/requests/geohash_fast_proto.py index 12071bc..ef9225c 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 2ee1bb1..f632251 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 f0453c7..3f44d24 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: