Skip to content

feat: add GeoJSON, KML, and vector tile endpoints (ERA-12686)#42

Open
JoshuaVulcan wants to merge 5 commits intomainfrom
ERA-12686-impl
Open

feat: add GeoJSON, KML, and vector tile endpoints (ERA-12686)#42
JoshuaVulcan wants to merge 5 commits intomainfrom
ERA-12686-impl

Conversation

@JoshuaVulcan
Copy link
Copy Markdown
Contributor

@JoshuaVulcan JoshuaVulcan commented Feb 11, 2026

Summary

Implements format-specific export methods in both ERClient (sync) and AsyncERClient (async):

  • GeoJSON (returns parsed JSON):

    • get_events_geojson(**kwargs) — events as GeoJSON FeatureCollection
    • get_subjects_geojson(**kwargs) — subjects as GeoJSON FeatureCollection
  • KML (returns raw response with binary KMZ):

    • get_subjects_kml(start, end, include_inactive) — all subjects KML document
    • get_subject_kml(subject_id, start, end) — single subject KML document
  • Vector tiles (returns raw response with binary PBF):

    • get_observation_segment_tiles(z, x, y) — observation segment MVT tiles
    • get_spatial_feature_tiles(z, x, y) — spatial feature MVT tiles

Also adds _get_response() async helper to AsyncERClient for endpoints that return binary content instead of JSON.

Test plan

  • 16 new sync tests in tests/sync_client/test_geojson_kml_tiles.py
  • 17 new async tests in tests/async_client/test_geojson_kml_tiles.py
  • All 120 tests pass (33 new + 87 existing)
  • Tests cover happy paths for all 6 new endpoints (both sync and async)
  • Tests verify correct URL construction and parameter passing
  • Tests verify response type (JSON vs raw response) per endpoint
  • Tests cover error handling (404 Not Found) for async client

Related

  • Jira: ERA-12686

Add get_events_export(filter=None) to AsyncERClient for parity with the
existing sync method.  Because the endpoint returns a CSV file rather
than JSON, a new _get_raw() helper is introduced that returns the raw
httpx.Response without attempting JSON parsing while preserving the
standard error-handling pipeline.

Also adds comprehensive tests for both the sync and async
get_events_export() methods covering success, filter forwarding, URL
construction, and error cases (401, 403, 404, 500).

Co-authored-by: Cursor <cursoragent@cursor.com>
@JoshuaVulcan JoshuaVulcan added autoreviewing PR is currently being auto-reviewed and removed autoreviewing PR is currently being auto-reviewed labels Feb 11, 2026
JoshuaVulcan added a commit that referenced this pull request Feb 11, 2026
- Add AsyncERClient._get_raw() to return raw httpx.Response for binary endpoints
- Use _get_raw in async download_choice_icons() and get_sitrep() so callers
  get response.content / stream instead of broken JSON parse
- Update async tests to mock binary content and assert on response.content

Addresses ER_CLIENT_PR_REVIEWS.md: PR #41 dependency check and get_sitrep
binary response. Self-contained (no dependency on PR #42 _get_response).

Co-authored-by: Cursor <cursoragent@cursor.com>
Use _get_raw (from PR #33) for raw GET responses instead of adding
_get_response; rebased onto ERA-12670/async-events-export.

Co-authored-by: Cursor <cursoragent@cursor.com>
JoshuaVulcan added a commit that referenced this pull request Feb 11, 2026
- Add AsyncERClient._get_raw() to return raw httpx.Response for binary endpoints
- Use _get_raw in async download_choice_icons() and get_sitrep() so callers
  get response.content / stream instead of broken JSON parse
- Update async tests to mock binary content and assert on response.content

Addresses ER_CLIENT_PR_REVIEWS.md: PR #41 dependency check and get_sitrep
binary response. Self-contained (no dependency on PR #42 _get_response).

Co-authored-by: Cursor <cursoragent@cursor.com>
JoshuaVulcan and others added 2 commits February 11, 2026 10:59
# Conflicts:
#	tests/sync_client/conftest.py
@JoshuaVulcan JoshuaVulcan requested a review from a team as a code owner February 12, 2026 02:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds new export/retrieval endpoints to the sync ERClient and async AsyncERClient for geospatial formats (GeoJSON FeatureCollections, KML/KMZ downloads, and MVT/PBF vector tiles), plus test coverage for these additions.

Changes:

  • Add sync + async client methods for GeoJSON, KML/KMZ, and vector tile (PBF) endpoints.
  • Add async helper _get_raw() to return httpx.Response for non-JSON/binary endpoints (and use it for CSV/KML/PBF calls).
  • Add new sync + async tests validating URL construction, parameter forwarding, response types, and async error handling.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
erclient/client.py Adds new GeoJSON/KML/tiles methods to both clients, plus async raw-response GET helper and async CSV export method.
tests/sync_client/test_get_events_export.py New sync tests verifying CSV export returns raw response and raises appropriate sync exceptions.
tests/sync_client/test_geojson_kml_tiles.py New sync tests for GeoJSON, KML/KMZ, and vector tile endpoints (URL/params/response type).
tests/async_client/test_get_events_export.py New async tests verifying CSV export returns raw httpx.Response and error mapping via _get_raw().
tests/async_client/test_geojson_kml_tiles.py New async tests for GeoJSON/KML/tiles endpoints, including 404 error handling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +1 to +12
import json
from unittest.mock import MagicMock, patch

import pytest

from erclient.er_errors import (
ERClientBadCredentials,
ERClientException,
ERClientNotFound,
ERClientPermissionDenied,
)

@@ -0,0 +1,239 @@
"""Tests for GeoJSON, KML, and vector tile endpoints in the sync ERClient."""
import json
from unittest.mock import patch, MagicMock
Comment on lines +1060 to +1071
"""
Get events as a GeoJSON FeatureCollection.

Accepts the same filter kwargs as get_events (state, event_type, filter, etc.).
:return: GeoJSON FeatureCollection dict
"""
params = dict((k, v) for k, v in kwargs.items() if k in
('state', 'page_size', 'page', 'event_type', 'filter',
'include_notes', 'include_related_events', 'include_files',
'include_details', 'updated_since', 'include_updates',
'oldest_update_date', 'event_ids'))
return self._get('activity/events/geojson', params=params)
Comment on lines +1728 to +1741
async def get_events_geojson(self, **kwargs):
"""
Get events as a GeoJSON FeatureCollection.

Accepts the same filter kwargs as get_events (state, event_type, filter, etc.).
:return: GeoJSON FeatureCollection dict
"""
params = {k: v for k, v in kwargs.items() if k in
('state', 'page_size', 'page', 'event_type', 'filter',
'include_notes', 'include_related_events', 'include_files',
'include_details', 'updated_since', 'include_updates',
'oldest_update_date', 'event_ids')}
return await self._get('activity/events/geojson', params=params)

async def _get_raw(self, path, params=None, base_url=None):
"""Issue a GET and return the raw httpx.Response (no JSON parsing).

Useful for endpoints that return non-JSON payloads (e.g. CSV, GeoJSON, KML).
Comment on lines +1853 to +1854
async def _get_raw(self, path, params=None, base_url=None):
"""Issue a GET and return the raw httpx.Response (no JSON parsing).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants