Skip to content

ERA-12662: Subject and source write parity (sync + async)#32

Open
JoshuaVulcan wants to merge 6 commits intomainfrom
ERA-12662/subject-source-write-parity
Open

ERA-12662: Subject and source write parity (sync + async)#32
JoshuaVulcan wants to merge 6 commits intomainfrom
ERA-12662/subject-source-write-parity

Conversation

@JoshuaVulcan
Copy link
Contributor

@JoshuaVulcan JoshuaVulcan commented Feb 11, 2026

Summary

  • Fills sync/async gaps for subject and source write operations, achieving full parity
  • Adds patch_subject(), get_source_subjects(), and get_source_assignments() to sync ERClient (previously async-only)
  • Adds post_subject(), delete_subject(), post_source(), delete_source() and _delete() helper to AsyncERClient (previously sync-only)
  • Includes comprehensive tests (async via respx + sync via unittest.mock) covering success, error handling, and parameter filtering

New Methods

Sync ERClient (new):

  • patch_subject(subject_id, data) - partial update a subject
  • get_source_subjects(source_id) - get all subjects linked to a source
  • get_source_assignments(subject_ids=None, source_ids=None) - list subject-source links with optional filtering

Async AsyncERClient (new):

  • post_subject(subject) - create a new subject
  • delete_subject(subject_id) - delete a subject
  • post_source(source) - create a new source
  • delete_source(source_id) - delete a source
  • _delete(path) - internal async DELETE helper

Test Plan

  • All 126 tests pass (90 existing + 36 new for subject/source write parity)
  • Sync tests cover: patch_subject, get_source_subjects, get_source_assignments, post_subject, delete_subject, post_source, delete_source
  • Async tests cover: post_subject, delete_subject, post_source, delete_source (plus existing patch_subject, get_source_subjects, get_source_assignments)
  • Manual QA against a staging ER instance

Jira

ERA-12662

@JoshuaVulcan JoshuaVulcan added autoreviewing PR is currently being auto-reviewed and removed autoreviewing PR is currently being auto-reviewed labels Feb 11, 2026
JoshuaVulcan and others added 2 commits February 11, 2026 10:17
Fill sync/async gaps for subject and source write operations:

Sync ERClient additions:
- patch_subject(subject_id, data) for partial subject updates
- get_source_assignments(subject_ids, source_ids) with optional filtering

Async AsyncERClient additions:
- post_subject(subject) to create new subjects
- delete_subject(subject_id) to remove subjects
- post_source(source) to create new sources
- delete_source(source_id) to remove sources
- _delete() helper method for DELETE HTTP operations

Includes 16 new tests (async + sync) covering success paths, error
handling (not found, forbidden, bad request, network errors), and
parameter filtering for source assignments.

Co-authored-by: Cursor <cursoragent@cursor.com>
Adds TestGetSourceSubjects class to sync_client tests covering:
- successful retrieval with URL verification
- empty results handling
- 404 and 403 error cases

Co-authored-by: Cursor <cursoragent@cursor.com>
@JoshuaVulcan JoshuaVulcan force-pushed the ERA-12662/subject-source-write-parity branch from e9518f1 to 05520c9 Compare February 11, 2026 18:18
@JoshuaVulcan JoshuaVulcan requested a review from a team as a code owner February 12, 2026 01:55
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 missing subject/source write (and related read) endpoints to maintain sync/async API parity in ERClient and AsyncERClient, with new targeted test coverage for both clients.

Changes:

  • Add sync ERClient methods: patch_subject, get_source_subjects, get_source_assignments.
  • Add async AsyncERClient methods: post_subject, delete_subject, post_source, delete_source.
  • Add new sync + async test suites covering these parity endpoints.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
erclient/client.py Introduces new sync and async client methods for subject/source write and related listing operations.
tests/sync_client/test_subject_source_write.py Adds sync tests for new parity methods and verifies existing write methods.
tests/async_client/test_subject_source_write.py Adds async tests for new async subject/source write methods using respx.

💡 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 +179 to +231
# ---- get_source_subjects tests ----

class TestGetSourceSubjects:
def test_get_source_subjects_success(self, er_client):
source_subjects_response = {
"data": [
{
"content_type": "observations.subject",
"id": "d8ad9955-8301-43c4-9000-9a02f1cba675",
"name": "MMVessel",
"subject_type": "vehicle",
"subject_subtype": "vessel",
"is_active": True,
}
],
"status": {"code": 200, "message": "OK"},
}
with patch.object(er_client._http_session, 'get') as mock_get:
mock_get.return_value = _mock_response(200, source_subjects_response)
source_id = "119feb94-a6cc-4485-8614-06fb0abc2a9c"
result = er_client.get_source_subjects(source_id)
assert result == source_subjects_response["data"]
assert mock_get.called
url = mock_get.call_args[0][0]
assert f"source/{source_id}/subjects" in url

def test_get_source_subjects_empty(self, er_client):
empty_response = {
"data": [],
"status": {"code": 200, "message": "OK"},
}
with patch.object(er_client._http_session, 'get') as mock_get:
mock_get.return_value = _mock_response(200, empty_response)
result = er_client.get_source_subjects("119feb94-a6cc-4485-8614-06fb0abc2a9c")
assert result == []

def test_get_source_subjects_not_found(self, er_client):
with patch.object(er_client._http_session, 'get') as mock_get:
mock_get.return_value = _mock_response(
404, ok=False, text='{"status":{"detail":"not found"}}'
)
with pytest.raises(ERClientNotFound):
er_client.get_source_subjects("nonexistent-id")

def test_get_source_subjects_forbidden(self, er_client):
with patch.object(er_client._http_session, 'get') as mock_get:
mock_get.return_value = _mock_response(
403, ok=False, text='{"status":{"detail":"forbidden"}}'
)
with pytest.raises(ERClientPermissionDenied):
er_client.get_source_subjects("119feb94-a6cc-4485-8614-06fb0abc2a9c")


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