Skip to content

Commit 281ed3d

Browse files
committed
get_user_submissions returns generator object
1 parent 1fb0fbf commit 281ed3d

File tree

6 files changed

+123
-91
lines changed

6 files changed

+123
-91
lines changed

synapseclient/api/evaluation_services.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -487,12 +487,11 @@ async def get_evaluation_submissions(
487487
async def get_user_submissions(
488488
evaluation_id: str,
489489
user_id: Optional[str] = None,
490-
limit: int = 20,
491-
offset: int = 0,
490+
*,
492491
synapse_client: Optional["Synapse"] = None,
493-
) -> dict:
492+
) -> AsyncGenerator[Dict[str, Any], None]:
494493
"""
495-
Retrieves Submissions for a specified Evaluation queue and user.
494+
Generator to get all user Submissions for a specified Evaluation queue.
496495
If user_id is omitted, this returns the submissions of the caller.
497496
498497
<https://rest-docs.synapse.org/rest/GET/evaluation/evalId/submission.html>
@@ -501,28 +500,26 @@ async def get_user_submissions(
501500
evaluation_id: The ID of the evaluation queue.
502501
user_id: Optionally specify the ID of the user whose submissions will be returned.
503502
If omitted, this returns the submissions of the caller.
504-
limit: Limits the number of submissions in a single response. Default to 20.
505-
offset: The offset index determines where this page will start from.
506-
An index of 0 is the first submission. Default to 0.
507503
synapse_client: If not passed in and caching was not disabled by `Synapse.allow_client_caching(False)`
508504
this will use the last created instance from the Synapse class constructor.
509505
510-
Returns:
511-
A response JSON containing a paginated list of user submissions for the evaluation queue.
506+
Yields:
507+
Individual Submission objects from each page of the response.
512508
"""
513509
from synapseclient import Synapse
514510

515511
client = Synapse.get_client(synapse_client=synapse_client)
516512

517513
uri = f"/evaluation/{evaluation_id}/submission"
518-
query_params = {"limit": limit, "offset": offset}
514+
query_params = {}
519515

520516
if user_id:
521517
query_params["userId"] = user_id
522518

523-
response = await client.rest_get_async(uri, params=query_params)
524-
525-
return response
519+
async for item in rest_get_paginated_async(
520+
uri=uri, params=query_params, synapse_client=client
521+
):
522+
yield item
526523

527524

528525
async def get_submission_count(

synapseclient/models/submission.py

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -192,32 +192,28 @@ def get_evaluation_submissions(
192192
synapse_client=synapse_client,
193193
)
194194

195-
@staticmethod
195+
@classmethod
196196
def get_user_submissions(
197+
cls,
197198
evaluation_id: str,
198199
user_id: Optional[str] = None,
199-
limit: int = 20,
200-
offset: int = 0,
201200
*,
202201
synapse_client: Optional[Synapse] = None,
203-
) -> Dict:
202+
) -> Generator["Submission", None, None]:
204203
"""
205-
Retrieves Submissions for a specified Evaluation queue and user.
204+
Retrieves all user Submissions for a specified Evaluation queue.
206205
If user_id is omitted, this returns the submissions of the caller.
207206
208207
Arguments:
209208
evaluation_id: The ID of the evaluation queue.
210209
user_id: Optionally specify the ID of the user whose submissions will be returned.
211210
If omitted, this returns the submissions of the caller.
212-
limit: Limits the number of submissions in a single response. Default to 20.
213-
offset: The offset index determines where this page will start from.
214-
An index of 0 is the first submission. Default to 0.
215211
synapse_client: If not passed in and caching was not disabled by
216212
`Synapse.allow_client_caching(False)` this will use the last created
217213
instance from the Synapse class constructor.
218214
219215
Returns:
220-
A response JSON containing a paginated list of user submissions for the evaluation queue.
216+
Submission objects as they are retrieved from the API.
221217
222218
Example: Getting user submissions
223219
```python
@@ -227,15 +223,19 @@ def get_user_submissions(
227223
syn = Synapse()
228224
syn.login()
229225
230-
response = Submission.get_user_submissions(
226+
submissions = list(Submission.get_user_submissions(
231227
evaluation_id="9999999",
232-
user_id="123456",
233-
limit=10
234-
)
235-
print(f"Found {len(response['results'])} user submissions")
228+
user_id="123456"
229+
))
230+
print(f"Found {len(submissions)} user submissions")
236231
```
237232
"""
238-
return {}
233+
yield from wrap_async_generator_to_sync_generator(
234+
async_gen_func=cls.get_user_submissions_async,
235+
evaluation_id=evaluation_id,
236+
user_id=user_id,
237+
synapse_client=synapse_client,
238+
)
239239

240240
@staticmethod
241241
def get_submission_count(
@@ -706,32 +706,29 @@ async def get_evaluation_submissions_example():
706706
submission_object = cls().fill_from_dict(synapse_submission=submission_data)
707707
yield submission_object
708708

709-
@staticmethod
709+
@skip_async_to_sync
710+
@classmethod
710711
async def get_user_submissions_async(
712+
cls,
711713
evaluation_id: str,
712714
user_id: Optional[str] = None,
713-
limit: int = 20,
714-
offset: int = 0,
715715
*,
716716
synapse_client: Optional[Synapse] = None,
717-
) -> Dict:
717+
) -> AsyncGenerator["Submission", None]:
718718
"""
719-
Retrieves Submissions for a specified Evaluation queue and user.
719+
Generator to get all user Submissions for a specified Evaluation queue.
720720
If user_id is omitted, this returns the submissions of the caller.
721721
722722
Arguments:
723723
evaluation_id: The ID of the evaluation queue.
724724
user_id: Optionally specify the ID of the user whose submissions will be returned.
725725
If omitted, this returns the submissions of the caller.
726-
limit: Limits the number of submissions in a single response. Default to 20.
727-
offset: The offset index determines where this page will start from.
728-
An index of 0 is the first submission. Default to 0.
729726
synapse_client: If not passed in and caching was not disabled by
730727
`Synapse.allow_client_caching(False)` this will use the last created
731728
instance from the Synapse class constructor.
732729
733-
Returns:
734-
A response JSON containing a paginated list of user submissions for the evaluation queue.
730+
Yields:
731+
Individual Submission objects from each page of the response.
735732
736733
Example: Getting user submissions
737734
```python
@@ -743,23 +740,24 @@ async def get_user_submissions_async(
743740
syn.login()
744741
745742
async def get_user_submissions_example():
746-
response = await Submission.get_user_submissions_async(
743+
submissions = []
744+
async for submission in Submission.get_user_submissions_async(
747745
evaluation_id="9999999",
748-
user_id="123456",
749-
limit=10
750-
)
751-
print(f"Found {len(response['results'])} user submissions")
746+
user_id="123456"
747+
):
748+
submissions.append(submission)
749+
print(f"Found {len(submissions)} user submissions")
752750
753751
asyncio.run(get_user_submissions_example())
754752
```
755753
"""
756-
return await evaluation_services.get_user_submissions(
754+
async for submission_data in evaluation_services.get_user_submissions(
757755
evaluation_id=evaluation_id,
758756
user_id=user_id,
759-
limit=limit,
760-
offset=offset,
761757
synapse_client=synapse_client,
762-
)
758+
):
759+
submission_object = cls().fill_from_dict(synapse_submission=submission_data)
760+
yield submission_object
763761

764762
@staticmethod
765763
async def get_submission_count_async(

tests/integration/synapseclient/models/async/test_submission_async.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -295,14 +295,34 @@ async def test_get_evaluation_submissions_async_generator_behavior(
295295
assert all(isinstance(sub, Submission) for sub in submissions)
296296

297297
async def test_get_user_submissions_async(self, test_evaluation: Evaluation):
298-
# WHEN I get submissions for the current user using async method
299-
response = await Submission.get_user_submissions_async(
298+
# WHEN I get submissions for the current user using async generator
299+
submissions = []
300+
async for submission in Submission.get_user_submissions_async(
300301
evaluation_id=test_evaluation.id, synapse_client=self.syn
301-
)
302+
):
303+
submissions.append(submission)
302304

303-
# THEN I should get a response with user submissions
304-
assert "results" in response
305+
# THEN all submissions should be valid Submission objects
305306
# Note: Could be empty if user hasn't made submissions to this evaluation
307+
assert all(isinstance(sub, Submission) for sub in submissions)
308+
309+
async def test_get_user_submissions_async_generator_behavior(
310+
self, test_evaluation: Evaluation
311+
):
312+
# WHEN I get user submissions using the async generator
313+
submissions_generator = Submission.get_user_submissions_async(
314+
evaluation_id=test_evaluation.id,
315+
synapse_client=self.syn,
316+
)
317+
318+
# THEN I should be able to iterate through the results
319+
submissions = []
320+
async for submission in submissions_generator:
321+
assert isinstance(submission, Submission)
322+
submissions.append(submission)
323+
324+
# AND all submissions should be valid Submission objects
325+
assert all(isinstance(sub, Submission) for sub in submissions)
306326

307327
async def test_get_submission_count_async(self, test_evaluation: Evaluation):
308328
# WHEN I get the submission count for an evaluation using async method

tests/integration/synapseclient/models/synchronous/test_submission.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,32 @@ async def test_get_evaluation_submissions_generator_behavior(
285285

286286
async def test_get_user_submissions(self, test_evaluation: Evaluation):
287287
# WHEN I get submissions for the current user
288-
response = Submission.get_user_submissions(
288+
submissions_generator = Submission.get_user_submissions(
289289
evaluation_id=test_evaluation.id, synapse_client=self.syn
290290
)
291291

292-
# THEN I should get a response with user submissions
293-
assert "results" in response
292+
# THEN I should get a generator that yields Submission objects
293+
submissions = list(submissions_generator)
294294
# Note: Could be empty if user hasn't made submissions to this evaluation
295+
assert all(isinstance(sub, Submission) for sub in submissions)
296+
297+
async def test_get_user_submissions_generator_behavior(
298+
self, test_evaluation: Evaluation
299+
):
300+
# WHEN I get user submissions using the generator
301+
submissions_generator = Submission.get_user_submissions(
302+
evaluation_id=test_evaluation.id,
303+
synapse_client=self.syn,
304+
)
305+
306+
# THEN I should be able to iterate through the results
307+
submissions = []
308+
for submission in submissions_generator:
309+
assert isinstance(submission, Submission)
310+
submissions.append(submission)
311+
312+
# AND all submissions should be valid Submission objects
313+
assert all(isinstance(sub, Submission) for sub in submissions)
295314

296315
async def test_get_submission_count(self, test_evaluation: Evaluation):
297316
# WHEN I get the submission count for an evaluation

tests/unit/synapseclient/models/async/unit_test_submission_async.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -515,37 +515,36 @@ async def test_get_user_submissions_async(self) -> None:
515515
# GIVEN user submission parameters
516516
evaluation_id = EVALUATION_ID
517517
user_id = USER_ID
518-
limit = 15
519-
offset = 0
520-
521-
expected_response = {
522-
"results": [self.get_example_submission_response()],
523-
"totalNumberOfResults": 1,
524-
}
525518

526519
# WHEN I call get_user_submissions_async
527520
with patch(
528-
"synapseclient.api.evaluation_services.get_user_submissions",
529-
new_callable=AsyncMock,
530-
return_value=expected_response,
521+
"synapseclient.api.evaluation_services.get_user_submissions"
531522
) as mock_get_user_submissions:
532-
response = await Submission.get_user_submissions_async(
523+
# Create an async generator function that yields submission data
524+
async def mock_async_gen(*args, **kwargs):
525+
submission_data = self.get_example_submission_response()
526+
yield submission_data
527+
528+
# Make the mock return our async generator when called
529+
mock_get_user_submissions.side_effect = mock_async_gen
530+
531+
submissions = []
532+
async for submission in Submission.get_user_submissions_async(
533533
evaluation_id=evaluation_id,
534534
user_id=user_id,
535-
limit=limit,
536-
offset=offset,
537535
synapse_client=self.syn,
538-
)
536+
):
537+
submissions.append(submission)
539538

540-
# THEN it should call the API with correct parameters
539+
# THEN it should call the API with correct parameters and yield Submission objects
541540
mock_get_user_submissions.assert_called_once_with(
542541
evaluation_id=evaluation_id,
543542
user_id=user_id,
544-
limit=limit,
545-
offset=offset,
546543
synapse_client=self.syn,
547544
)
548-
assert response == expected_response
545+
assert len(submissions) == 1
546+
assert isinstance(submissions[0], Submission)
547+
assert submissions[0].id == SUBMISSION_ID
549548

550549
@pytest.mark.asyncio
551550
async def test_get_submission_count_async(self) -> None:

tests/unit/synapseclient/models/synchronous/unit_test_submission.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -678,37 +678,36 @@ async def test_get_user_submissions_async(self) -> None:
678678
# GIVEN user submission parameters
679679
evaluation_id = EVALUATION_ID
680680
user_id = USER_ID
681-
limit = 15
682-
offset = 0
683-
684-
expected_response = {
685-
"results": [self.get_example_submission_response()],
686-
"totalNumberOfResults": 1,
687-
}
688681

689682
# WHEN I call get_user_submissions_async
690683
with patch(
691-
"synapseclient.api.evaluation_services.get_user_submissions",
692-
new_callable=AsyncMock,
693-
return_value=expected_response,
684+
"synapseclient.api.evaluation_services.get_user_submissions"
694685
) as mock_get_user_submissions:
695-
response = await Submission.get_user_submissions_async(
686+
# Create an async generator function that yields submission data
687+
async def mock_async_gen(*args, **kwargs):
688+
submission_data = self.get_example_submission_response()
689+
yield submission_data
690+
691+
# Make the mock return our async generator when called
692+
mock_get_user_submissions.side_effect = mock_async_gen
693+
694+
submissions = []
695+
async for submission in Submission.get_user_submissions_async(
696696
evaluation_id=evaluation_id,
697697
user_id=user_id,
698-
limit=limit,
699-
offset=offset,
700698
synapse_client=self.syn,
701-
)
699+
):
700+
submissions.append(submission)
702701

703-
# THEN it should call the API with correct parameters
702+
# THEN it should call the API with correct parameters and yield Submission objects
704703
mock_get_user_submissions.assert_called_once_with(
705704
evaluation_id=evaluation_id,
706705
user_id=user_id,
707-
limit=limit,
708-
offset=offset,
709706
synapse_client=self.syn,
710707
)
711-
assert response == expected_response
708+
assert len(submissions) == 1
709+
assert isinstance(submissions[0], Submission)
710+
assert submissions[0].id == SUBMISSION_ID
712711

713712
@pytest.mark.asyncio
714713
async def test_get_submission_count_async(self) -> None:

0 commit comments

Comments
 (0)