Skip to content

ERA-12650: Add full patrol CRUD to both sync and async clients#28

Open
JoshuaVulcan wants to merge 7 commits intomainfrom
ERA-12650/patrol-methods-parity
Open

ERA-12650: Add full patrol CRUD to both sync and async clients#28
JoshuaVulcan wants to merge 7 commits intomainfrom
ERA-12650/patrol-methods-parity

Conversation

@JoshuaVulcan
Copy link
Contributor

@JoshuaVulcan JoshuaVulcan commented Feb 10, 2026

Summary

  • Adds comprehensive patrol endpoint coverage to both ERClient (sync) and AsyncERClient, achieving full sync/async parity for patrol operations
  • Covers all patrol-related DAS API endpoints: patrols, patrol types, patrol segments, patrol notes, patrol files, and the tracked-by schema
  • Adds _delete() helper to AsyncERClient to enable DELETE operations (previously missing)
  • Includes 33 new tests (async via respx + sync via unittest.mock) covering success paths, pagination, error handling, and all CRUD operations

New Methods

Sync ERClient (new):

  • get_patrol(id), patch_patrol(id, data)
  • get_patrol_types(), get_patrol_type(id), post_patrol_type(), patch_patrol_type(), delete_patrol_type()
  • get_patrol_segments(), get_patrol_segment(id), post_patrol_segment(), patch_patrol_segment(), get_patrol_segment_events()
  • get_patrol_notes(), post_patrol_note(), patch_patrol_note(), delete_patrol_note()
  • get_patrol_files(), post_patrol_file(), get_patrol_file()
  • get_patrol_trackedby()

Async AsyncERClient (new):

  • get_patrols() (async generator with pagination), get_patrol(), post_patrol(), patch_patrol(), delete_patrol()
  • All patrol types, segments, notes, files, and tracked-by methods (mirrors sync)
  • add_events_to_patrol_segment()

Test Plan

  • All 33 new patrol tests pass (async + sync)
  • All 108 existing tests continue to pass (141 total)
  • Manual QA against a staging ER instance

Jira

ERA-12650

@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
…g to _call()

- Async _delete() now delegates to _call(path=path, payload=None, method='DELETE', params=params)
- Add 204 / empty-body handling in async _call() so DELETE responses don't trigger JSON parse
- Aligns with PR review: use _call() delegation pattern like PRs #28, #29, #34; reduces merge conflict

Co-authored-by: Cursor <cursoragent@cursor.com>
JoshuaVulcan and others added 3 commits February 11, 2026 10:16
Adds comprehensive patrol endpoint coverage to ERClient and AsyncERClient:

Sync client additions:
- get_patrol(), patch_patrol() (single patrol detail/update)
- Patrol types CRUD (get/post/patch/delete)
- Patrol segments CRUD + get_patrol_segment_events()
- Patrol notes CRUD
- Patrol files (get/post/get single)
- get_patrol_trackedby() schema endpoint

Async client additions (all patrol methods, achieving full parity):
- get_patrols() as async generator with pagination
- get_patrol(), post_patrol(), patch_patrol(), delete_patrol()
- All patrol types, segments, notes, files methods
- add_events_to_patrol_segment()
- _delete() helper method on AsyncERClient

Includes 33 new tests (async + sync) covering success, pagination,
error handling, and all CRUD operations.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Make async post_patrol_file(patrol_id, filepath, comment) take filepath and open
  file internally to match sync client and post_event_file() pattern
- Update async test_post_patrol_file to use tmp_path filepath instead of BytesIO
- Add get_patrol 403 (forbidden) tests for both sync and async
- Add delete_patrol 404/403 tests for async; add full delete_patrol tests for
  sync (success, not_found, forbidden)

Co-authored-by: Cursor <cursoragent@cursor.com>
- Add responses>=0.24 to test optional deps and dev dependency group
- Replace patch.object/MagicMock with @responses.activate and
  responses.get/post/patch/delete to validate full URL construction
- Add _url() helper to build API URLs like ERClient._er_url()
- Assert request URLs where useful (get_patrol, delete_patrol, add_events)

Co-authored-by: Cursor <cursoragent@cursor.com>
JoshuaVulcan and others added 3 commits February 11, 2026 10:54
# Conflicts:
#	tests/sync_client/conftest.py
…root

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@JoshuaVulcan JoshuaVulcan requested a review from a team as a code owner February 12, 2026 01:43
Copy link
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 full patrol CRUD coverage across the sync (ERClient) and async (AsyncERClient) clients to achieve endpoint parity, along with new sync/async test suites and required test dependencies.

Changes:

  • Added patrol endpoints for types/segments/notes/files/tracked-by to ERClient and AsyncERClient, plus async pagination via get_patrols().
  • Added new patrol-focused test suites for both sync (responses) and async (respx) clients.
  • Added responses as a dev/test dependency (pyproject + lockfile updates).

Reviewed changes

Copilot reviewed 4 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 sync + async patrol methods (CRUD + related endpoints).
tests/sync_client/test_patrols.py New sync patrol test coverage using responses.
tests/async_client/test_patrols.py New async patrol test coverage using respx, including pagination and error handling.
pyproject.toml Adds responses to dev/test dependencies.
uv.lock Locks responses dependency.

💡 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.

import responses

from erclient import ERClientNotFound, ERClientPermissionDenied
from erclient.client import ERClient
Comment on lines +1 to +3
import pytest
import responses


def delete_patrol_type(self, patrol_type_id):
"""Delete a patrol type."""
return self._delete(f'activity/patrols/types/{patrol_type_id}')
Comment on lines +686 to +694
def post_patrol_file(self, patrol_id, filepath, comment=''):
"""Upload a file to a patrol."""
with open(filepath, 'rb') as f:
files = {'filecontent.file': f}
return self._post_form(
f'activity/patrols/{patrol_id}/files/',
body={'comment': comment},
files=files,
)
Comment on lines +1746 to +1748
async def delete_patrol(self, patrol_id):
"""Delete a patrol."""
return await self._delete(f'activity/patrols/{patrol_id}/')
Comment on lines +1828 to +1836
async def post_patrol_file(self, patrol_id, filepath, comment=''):
"""Upload a file to a patrol."""
with open(filepath, 'rb') as f:
files = {'filecontent.file': f}
return await self._post_form(
f'activity/patrols/{patrol_id}/files/',
body={'comment': comment},
files=files,
)
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