|
7 | 7 | import logging |
8 | 8 | import os |
9 | 9 | import tempfile |
| 10 | +import typing |
10 | 11 | import urllib.request as urllib_request |
11 | 12 | import uuid |
12 | 13 | from pathlib import Path |
|
59 | 60 | ) |
60 | 61 | from synapseclient.core.models.dict_object import DictObject |
61 | 62 | from synapseclient.core.upload import upload_functions |
| 63 | +from synapseclient.evaluation import Submission, SubmissionStatus |
62 | 64 |
|
63 | 65 | GET_FILE_HANDLE_FOR_DOWNLOAD = ( |
64 | 66 | "synapseclient.core.download.download_functions.get_file_handle_for_download_async" |
@@ -2995,6 +2997,156 @@ def test_get_submission_with_annotations(syn: Synapse) -> None: |
2995 | 2997 | assert evaluation_id == response["evaluationId"] |
2996 | 2998 |
|
2997 | 2999 |
|
| 3000 | +def run_get_submission_test( |
| 3001 | + syn: Synapse, |
| 3002 | + submission_id: typing.Union[str, int], |
| 3003 | + expected_id: str, |
| 3004 | + should_warn: bool = False, |
| 3005 | + caplog=None, |
| 3006 | +) -> None: |
| 3007 | + """ |
| 3008 | + Common code for test_get_submission_valid_id and test_get_submission_invalid_id. |
| 3009 | + Generates a dummy submission dictionary for regression testing, mocks the API calls, |
| 3010 | + and validates the expected output for getSubmission. For invalid submission IDs, this |
| 3011 | + will check that a warning was logged for the user before transforming their input. |
| 3012 | +
|
| 3013 | + Arguments: |
| 3014 | + syn: Synapse object |
| 3015 | + submission_id: Submission ID to test |
| 3016 | + expected_id: Submission ID that should be returned |
| 3017 | + should_warn: Whether or not a warning should be logged |
| 3018 | + caplog: pytest caplog fixture |
| 3019 | +
|
| 3020 | + Returns: |
| 3021 | + None |
| 3022 | +
|
| 3023 | + """ |
| 3024 | + evaluation_id = (98765,) |
| 3025 | + submission = { |
| 3026 | + "evaluationId": evaluation_id, |
| 3027 | + "entityId": submission_id, |
| 3028 | + "versionNumber": 1, |
| 3029 | + "entityBundleJSON": json.dumps({}), |
| 3030 | + } |
| 3031 | + |
| 3032 | + with patch.object(syn, "restGET") as restGET, patch.object( |
| 3033 | + syn, "_getWithEntityBundle" |
| 3034 | + ) as get_entity: |
| 3035 | + restGET.return_value = submission |
| 3036 | + |
| 3037 | + if should_warn: |
| 3038 | + with caplog.at_level(logging.WARNING): |
| 3039 | + syn.getSubmission(submission_id) |
| 3040 | + assert f"contains decimals which are not supported" in caplog.text |
| 3041 | + else: |
| 3042 | + syn.getSubmission(submission_id) |
| 3043 | + |
| 3044 | + restGET.assert_called_once_with(f"/evaluation/submission/{expected_id}") |
| 3045 | + get_entity.assert_called_once_with( |
| 3046 | + entityBundle={}, |
| 3047 | + entity=submission_id, |
| 3048 | + submission=str(expected_id), |
| 3049 | + ) |
| 3050 | + |
| 3051 | + |
| 3052 | +@pytest.mark.parametrize( |
| 3053 | + "submission_id, expected_id", |
| 3054 | + [("123", "123"), (123, "123"), ({"id": 123}, "123"), ({"id": "123"}, "123")], |
| 3055 | +) |
| 3056 | +def test_get_submission_valid_id(syn: Synapse, submission_id, expected_id) -> None: |
| 3057 | + """Test getSubmission with valid submission ID""" |
| 3058 | + run_get_submission_test(syn, submission_id, expected_id) |
| 3059 | + |
| 3060 | + |
| 3061 | +@pytest.mark.parametrize( |
| 3062 | + "submission_id, expected_id", |
| 3063 | + [ |
| 3064 | + ("123.0", "123"), |
| 3065 | + (123.0, "123"), |
| 3066 | + ({"id": 123.0}, "123"), |
| 3067 | + ({"id": "123.0"}, "123"), |
| 3068 | + ], |
| 3069 | +) |
| 3070 | +def test_get_submission_invalid_id( |
| 3071 | + syn: Synapse, submission_id, expected_id, caplog |
| 3072 | +) -> None: |
| 3073 | + """Test getSubmission with invalid submission ID""" |
| 3074 | + run_get_submission_test( |
| 3075 | + syn, submission_id, expected_id, should_warn=True, caplog=caplog |
| 3076 | + ) |
| 3077 | + |
| 3078 | + |
| 3079 | +def test_get_submission_and_submission_status_interchangeability( |
| 3080 | + syn: Synapse, caplog |
| 3081 | +) -> None: |
| 3082 | + """Test interchangeability of getSubmission and getSubmissionStatus.""" |
| 3083 | + |
| 3084 | + # Establish some dummy variables to work with |
| 3085 | + evaluation_id = 98765 |
| 3086 | + submission_id = 9745366.0 |
| 3087 | + expected_submission_id = "9745366" |
| 3088 | + |
| 3089 | + # Establish an expected return for `getSubmissionStatus` |
| 3090 | + submission_status_return = { |
| 3091 | + "id": expected_submission_id, |
| 3092 | + "etag": "000", |
| 3093 | + "status": "RECEIVED", |
| 3094 | + } |
| 3095 | + |
| 3096 | + # Establish an expected return for `getSubmission` |
| 3097 | + submission_return = { |
| 3098 | + "id": expected_submission_id, |
| 3099 | + "evaluationId": evaluation_id, |
| 3100 | + "entityId": expected_submission_id, |
| 3101 | + "versionNumber": 1, |
| 3102 | + "entityBundleJSON": json.dumps({}), |
| 3103 | + } |
| 3104 | + |
| 3105 | + # Let's mock all the API calls made within these two methods |
| 3106 | + with patch.object(syn, "restGET") as restGET, patch.object( |
| 3107 | + Submission, "getURI" |
| 3108 | + ) as get_submission_uri, patch.object( |
| 3109 | + SubmissionStatus, "getURI" |
| 3110 | + ) as get_status_uri, patch.object( |
| 3111 | + syn, "_getWithEntityBundle" |
| 3112 | + ): |
| 3113 | + get_submission_uri.return_value = ( |
| 3114 | + f"/evaluation/submission/{expected_submission_id}" |
| 3115 | + ) |
| 3116 | + get_status_uri.return_value = ( |
| 3117 | + f"/evaluation/submission/{expected_submission_id}/status" |
| 3118 | + ) |
| 3119 | + |
| 3120 | + # Establish a return for all the calls to restGET we will be making in this test |
| 3121 | + restGET.side_effect = [ |
| 3122 | + # Step 1 call to `getSubmission` |
| 3123 | + submission_return, |
| 3124 | + # Step 2 call to `getSubmissionStatus` |
| 3125 | + submission_status_return, |
| 3126 | + ] |
| 3127 | + |
| 3128 | + # Step 1: Call `getSubmission` with float ID |
| 3129 | + restGET.return_value = submission_return |
| 3130 | + submission_result = syn.getSubmission(submission_id) |
| 3131 | + |
| 3132 | + # Step 2: Call `getSubmissionStatus` with the `Submission` object from above |
| 3133 | + restGET.reset_mock() |
| 3134 | + restGET.return_value = submission_status_return |
| 3135 | + submission_status_result = syn.getSubmissionStatus(submission_result) |
| 3136 | + |
| 3137 | + # Validate that getSubmission and getSubmissionStatus are called with correct URIs |
| 3138 | + # in `getURI` calls |
| 3139 | + get_submission_uri.assert_called_once_with(expected_submission_id) |
| 3140 | + get_status_uri.assert_called_once_with(expected_submission_id) |
| 3141 | + |
| 3142 | + # Validate final output is as expected |
| 3143 | + assert ( |
| 3144 | + submission_result["id"] |
| 3145 | + == submission_status_result["id"] |
| 3146 | + == expected_submission_id |
| 3147 | + ) |
| 3148 | + |
| 3149 | + |
2998 | 3150 | class TestTableSnapshot: |
2999 | 3151 | def test__create_table_snapshot(self, syn: Synapse) -> None: |
3000 | 3152 | """Testing creating table snapshots""" |
|
0 commit comments