Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 208 additions & 0 deletions erclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,93 @@ def get_sources(self, page_size=100):
def get_users(self):
return self._get('users')

# ── Analyzers ─────────────────────────────────────────────────

def get_analyzers_spatial(self):
"""List spatial analyzers."""
return self._get('analyzers/spatial')

def get_analyzers_subject(self):
"""List subject analyzers."""
return self._get('analyzers/subject')

# ── Choices ───────────────────────────────────────────────────

def get_choices(self):
"""List all choice sets."""
return self._get('choices')

def get_choice(self, choice_id):
"""Get a single choice set by ID.

:param choice_id: UUID of the choice set.
"""
return self._get(f'choices/{choice_id}')

def download_choice_icons(self):
"""Download the choice icons zip file.

Returns the raw :class:`requests.Response` so the caller can
stream or save the binary content.
"""
return self._get('choices/icons/download', return_response=True)

# ── Buoy / Gear ──────────────────────────────────────────────

def get_gear_list(self):
"""List all buoy/gear items."""
return self._get('buoy/gear')

def get_gear(self, gear_id):
"""Get a single gear item by ID.

:param gear_id: UUID of the gear item.
"""
return self._get(f'buoy/gear/{gear_id}')

def post_gear(self, gear):
"""Create a new gear item.

:param gear: dict with gear payload.
"""
return self._post('buoy/gear', payload=gear)

def patch_gear(self, gear_id, gear):
"""Update an existing gear item.

:param gear_id: UUID of the gear item.
:param gear: dict with partial gear payload.
"""
return self._patch(f'buoy/gear/{gear_id}', payload=gear)

def delete_gear(self, gear_id):
"""Delete a gear item.

:param gear_id: UUID of the gear item.
"""
return self._delete(f'buoy/gear/{gear_id}')

# ── Reports / Tableau ─────────────────────────────────────────

def get_sitrep(self):
"""Download the situation report (.docx).

Returns the raw :class:`requests.Response` so the caller can
stream or save the binary content.
"""
return self._get('reports/sitrep.docx', return_response=True)

def get_tableau_views(self):
"""List available Tableau views."""
return self._get('reports/tableau-views')

def get_tableau_view(self, view_id):
"""Get a single Tableau view by ID.

:param view_id: UUID of the tableau view.
"""
return self._get(f'reports/tableau-views/{view_id}')


class AsyncERClient(object):
"""
Expand Down Expand Up @@ -1613,6 +1700,93 @@ async def get_feature_group(self, feature_group_id: str):
"""
return await self._get(f"spatialfeaturegroup/{feature_group_id}", params={})

# ── Analyzers ─────────────────────────────────────────────────

async def get_analyzers_spatial(self):
"""List spatial analyzers."""
return await self._get('analyzers/spatial')

async def get_analyzers_subject(self):
"""List subject analyzers."""
return await self._get('analyzers/subject')

# ── Choices ───────────────────────────────────────────────────

async def get_choices(self):
"""List all choice sets."""
return await self._get('choices')

async def get_choice(self, choice_id):
"""Get a single choice set by ID.

:param choice_id: UUID of the choice set.
"""
return await self._get(f'choices/{choice_id}')

async def download_choice_icons(self):
"""Download the choice icons zip file.

Returns the raw :class:`httpx.Response` so the caller can
stream or save the binary content (e.g. response.content).
"""
return await self._get_raw("choices/icons/download")

# ── Buoy / Gear ──────────────────────────────────────────────

async def get_gear_list(self):
"""List all buoy/gear items."""
return await self._get('buoy/gear')

async def get_gear(self, gear_id):
"""Get a single gear item by ID.

:param gear_id: UUID of the gear item.
"""
return await self._get(f'buoy/gear/{gear_id}')

async def post_gear(self, gear):
"""Create a new gear item.

:param gear: dict with gear payload.
"""
return await self._post('buoy/gear', payload=gear)

async def patch_gear(self, gear_id, gear):
"""Update an existing gear item.

:param gear_id: UUID of the gear item.
:param gear: dict with partial gear payload.
"""
return await self._patch(f'buoy/gear/{gear_id}', payload=gear)

async def delete_gear(self, gear_id):
"""Delete a gear item.

:param gear_id: UUID of the gear item.
"""
return await self._delete(f'buoy/gear/{gear_id}')

# ── Reports / Tableau ─────────────────────────────────────────

async def get_sitrep(self):
"""Download the situation report (.docx).

Returns the raw :class:`httpx.Response` so the caller can
stream or save the binary content (e.g. response.content).
"""
return await self._get_raw("reports/sitrep.docx")

async def get_tableau_views(self):
"""List available Tableau views."""
return await self._get('reports/tableau-views')

async def get_tableau_view(self, view_id):
"""Get a single Tableau view by ID.

:param view_id: UUID of the tableau view.
"""
return await self._get(f'reports/tableau-views/{view_id}')

async def _get_data(self, endpoint, params, batch_size=0):
if "page" not in params: # Use cursor paginator unless the user has specified a page
params["use_cursor"] = "true"
Expand Down Expand Up @@ -1723,6 +1897,40 @@ async def _delete(self, path, params=None, base_url=None):
path=path, payload=None, method="DELETE", params=params, base_url=base_url
)

async def _get_raw(self, path, params=None):
"""Perform a GET request and return the raw httpx.Response (for binary downloads)."""
try:
auth_headers = await self.auth_headers()
except httpx.HTTPStatusError as e:
self._handle_http_status_error(path, "GET", e)
params = params or {}
headers = {"User-Agent": self.user_agent, **auth_headers}
try:
response = await self._http_session.request(
"GET",
self._er_url(path),
params=params,
headers=headers,
)
response.raise_for_status()
return response
except httpx.RequestError as e:
Comment on lines +1900 to +1917
reason = str(e)
self.logger.error(
"Request to ER failed",
extra=dict(
provider_key=self.provider_key,
service=self.service_root,
path=path,
status_code=None,
reason=reason,
text="",
),
)
raise ERClientException(f"Request to ER failed: {reason}")
except httpx.HTTPStatusError as e:
self._handle_http_status_error(path, "GET", e)

async def _call(self, path, payload, method, params=None, base_url=None):
try:
auth_headers = await self.auth_headers()
Expand Down
Loading
Loading