Skip to content

docs: clarify sync vs async client usage, add method patterns and best practices#48

Open
JoshuaVulcan wants to merge 1 commit into
mainfrom
docs/readme-sync-async-and-patterns
Open

docs: clarify sync vs async client usage, add method patterns and best practices#48
JoshuaVulcan wants to merge 1 commit into
mainfrom
docs/readme-sync-async-and-patterns

Conversation

@JoshuaVulcan
Copy link
Copy Markdown
Contributor

@JoshuaVulcan JoshuaVulcan commented Feb 13, 2026

README updates:

  • Sync vs async: Table for when to use ERClient vs AsyncERClient; separate sections with constructor and usage patterns. Fixed async examples (correct client reference, async with + asyncio.run(main())).
  • Method patterns: Examples for single-item gets, paginated get_events/get_observations, and post_report/post_sensor_observation/post_event_file. Short reference for constructor and common method signatures.
  • Best practices: Use async with for async client; handle ERClientException and subclasses; timezone-aware times for filters; provider_key for sensors; large-read and rate-limit notes; link to EarthRanger docs.

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

Updates the README to better guide users on when and how to use the synchronous (ERClient) vs asynchronous (AsyncERClient) EarthRanger clients, and provides more concrete usage patterns and best-practice guidance.

Changes:

  • Adds a sync vs async decision table and separate usage sections for ERClient and AsyncERClient.
  • Introduces “common patterns” examples (single-item gets, paginated iteration, and common post methods).
  • Adds a reference-style section for common method signatures plus operational best practices (errors, time ranges, bulk reads, rate limits).

💡 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 thread README.md
The async client currently supports:

* **Post:** Sensor observations (positions), events/reports, event attachments, camera trap reports, messages; event/subject/event type/category CRUD where implemented.
* **Get:** Events, single event, event types, observations, subject groups, feature groups, sources, source assignments (subjectsources), user/me.
Comment thread README.md
Comment on lines +133 to +134
* **Constructor:** `ERClient(service_root, client_id=None, username=None, password=None, token=None, provider_key=None, ...)`
Same for `AsyncERClient`. Use `token` or `client_id`+`username`+`password`. Set `provider_key` when posting sensor/camera-trap data.
Comment thread README.md
Same for `AsyncERClient`. Use `token` or `client_id`+`username`+`password`. Set `provider_key` when posting sensor/camera-trap data.

* **Events:**
`get_events(*, filter, page_size, max_results, ...)` → sync: generator; async: async generator.
Comment thread README.md

* **Async:** Prefer `async with AsyncERClient(...) as client:` so the session is closed even on errors.
* **Errors:** Catch `ERClientException` and subclasses (`ERClientBadCredentials`, `ERClientNotFound`, `ERClientPermissionDenied`, `ERClientRateLimitExceeded`, `ERClientServiceUnreachable`, etc.) for robust handling.
* **Time ranges:** Use timezone-aware datetimes or ISO 8601 strings with timezone (e.g. `"2023-11-10T00:00:00-06:00"`) for `start`/`end` and filter `date_range` to avoid ambiguity.
Comment thread README.md
Comment on lines +65 to +66
for obs in client.get_observations(start="2023-11-10T00:00:00Z", end="2023-11-11T00:00:00Z"):
...
Comment thread README.md
Comment on lines +101 to +104
# Post (await)
await client.post_sensor_observation(position)
await client.post_report(report)
await client.post_camera_trap_report(camera_trap_payload, file=file_handle)
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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 8 comments.

Comment thread README.md
Comment on lines +63 to +66
for event in client.get_events(filter=..., max_results=100):
...
for obs in client.get_observations(start="2023-11-10T00:00:00Z", end="2023-11-11T00:00:00Z"):
...
Comment thread README.md
Comment on lines +47 to +52
client_id="example_client_id",
username="your_username",
password="your_password",
)
# Or with a bearer token
client = ERClient(service_root="https://sandbox.pamdas.org", token="your_bearer_token")
Comment thread README.md
Comment on lines +85 to +105
async with AsyncERClient(
service_root="https://sandbox.pamdas.org",
client_id="example_client_id",
username="your_username",
password="your_password",
) as client:
# Single-item calls: await
event = await client.get_event(event_id="uuid")
event_types = await client.get_event_types()

# Stream events or observations: async for
async for event in client.get_events(filter=..., page_size=100):
...
async for observation in client.get_observations(start="2023-11-10T00:00:00-06:00"):
...

# Post (await)
await client.post_sensor_observation(position)
await client.post_report(report)
await client.post_camera_trap_report(camera_trap_payload, file=file_handle)

Comment thread README.md
The async client currently supports:

* **Post:** Sensor observations (positions), events/reports, event attachments, camera trap reports, messages; event/subject/event type/category CRUD where implemented.
* **Get:** Events, single event, event types, observations, subject groups, feature groups, sources, source assignments (subjectsources), user/me.
Comment thread README.md
Same for `AsyncERClient`. Use `token` or `client_id`+`username`+`password`. Set `provider_key` when posting sensor/camera-trap data.

* **Events:**
`get_events(*, filter, page_size, max_results, ...)` → sync: generator; async: async generator.
Comment thread README.md

* **Async:** Prefer `async with AsyncERClient(...) as client:` so the session is closed even on errors.
* **Errors:** Catch `ERClientException` and subclasses (`ERClientBadCredentials`, `ERClientNotFound`, `ERClientPermissionDenied`, `ERClientRateLimitExceeded`, `ERClientServiceUnreachable`, etc.) for robust handling.
* **Time ranges:** Use timezone-aware datetimes or ISO 8601 strings with timezone (e.g. `"2023-11-10T00:00:00-06:00"`) for `start`/`end` and filter `date_range` to avoid ambiguity.
Comment thread README.md
* **Time ranges:** Use timezone-aware datetimes or ISO 8601 strings with timezone (e.g. `"2023-11-10T00:00:00-06:00"`) for `start`/`end` and filter `date_range` to avoid ambiguity.
* **Sensor/camera-trap posts:** Set `provider_key` on the client when posting sensor observations or camera trap reports.
* **Large reads:** Sync: consider `get_objects_multithreaded` for big list endpoints. Async: use `page_size` and optional `batch_size` in `get_events`/`get_observations`; cursor-based pagination is used by default.
* **Rate limits:** The API may throttle (e.g. one observation per second per source); the client raises `ERClientRateLimitExceeded` on 409/429. Back off and retry as needed.
Comment thread README.md
`post_sensor_observation(observation, sensor_type='generic')` → requires `provider_key`.

* **Single resources:**
`get_subject(subject_id)`, `get_source_by_id(id)`, `get_event_type(event_type_name, version=...)`, etc. return one object.
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

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

Comment thread README.md
Comment on lines +63 to +66
for event in client.get_events(filter=..., max_results=100):
...
for obs in client.get_observations(start="2023-11-10T00:00:00Z", end="2023-11-11T00:00:00Z"):
...
Comment thread README.md
Comment on lines +112 to +118
client = AsyncERClient(service_root="...", client_id="...", username="...", password="...")
try:
await client.post_report(report)
async for obs in client.get_observations(start="2023-11-10T00:00:00-06:00"):
print(obs)
finally:
await client.close()
Comment thread README.md
Same for `AsyncERClient`. Use `token` or `client_id`+`username`+`password`. Set `provider_key` when posting sensor/camera-trap data.

* **Events:**
`get_events(*, filter, page_size, max_results, ...)` → sync: generator; async: async generator.
Comment thread README.md
Comment on lines +141 to +143
* **Observations:**
`get_observations(*, subject_id, source_id, start, end, page_size, ...)` → sync: generator; async: async generator.
`post_sensor_observation(observation, sensor_type='generic')` → requires `provider_key`.
Comment thread README.md

* **Async:** Prefer `async with AsyncERClient(...) as client:` so the session is closed even on errors.
* **Errors:** Catch `ERClientException` and subclasses (`ERClientBadCredentials`, `ERClientNotFound`, `ERClientPermissionDenied`, `ERClientRateLimitExceeded`, `ERClientServiceUnreachable`, etc.) for robust handling.
* **Time ranges:** Use timezone-aware datetimes or ISO 8601 strings with timezone (e.g. `"2023-11-10T00:00:00-06:00"`) for `start`/`end` and filter `date_range` to avoid ambiguity.
Comment thread README.md
* **Time ranges:** Use timezone-aware datetimes or ISO 8601 strings with timezone (e.g. `"2023-11-10T00:00:00-06:00"`) for `start`/`end` and filter `date_range` to avoid ambiguity.
* **Sensor/camera-trap posts:** Set `provider_key` on the client when posting sensor observations or camera trap reports.
* **Large reads:** Sync: consider `get_objects_multithreaded` for big list endpoints. Async: use `page_size` and optional `batch_size` in `get_events`/`get_observations`; cursor-based pagination is used by default.
* **Rate limits:** The API may throttle (e.g. one observation per second per source); the client raises `ERClientRateLimitExceeded` on 409/429. Back off and retry as needed.
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.

3 participants