-
Notifications
You must be signed in to change notification settings - Fork 73
[SYNPY-1590] Implement core functionality of Submission(+Status, +Bundle) OOP model #1251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 43 commits
c748132
33643ae
8a074e6
c97b891
f79f683
99ebaa1
33c651f
ae05b91
f51188d
33f7a6a
4a91a2e
65eac22
a5ec33a
a160585
660259e
55a229c
3479046
896a3c1
26a02f1
271181a
c8c1041
0436931
cb48df2
dbe5f76
7c07af9
6a5e97b
9c2c0d1
aee4ccd
4a5fe53
480d5de
4ca53e0
3f25df8
b5839c3
5526b8d
bdeaaa7
7add157
35696eb
b8c0ee5
73c5f1a
8db9e67
53d9852
1561141
4d082c3
2272d47
134ad0c
48468c6
23a2779
72a4dd0
8dd2db4
b75c566
be4278a
5a70bd1
a54ade1
890005e
0b0fa0c
96f2dd7
acedf26
75bad96
ea52424
f08a6ad
e5189d6
42d0c54
8ef400a
05e5218
7c7d474
40e95cd
64395dd
0765d1c
6a8432b
d5bff02
ad5f833
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -228,6 +228,127 @@ def to_submission_status_annotations(annotations, is_private=True): | |
| return synapseAnnos | ||
|
|
||
|
|
||
| def to_submission_annotations( | ||
| id: typing.Union[str, int], | ||
| etag: str, | ||
| annotations: typing.Dict[str, typing.Any], | ||
| logger: typing.Optional[typing.Any] = None, | ||
jaymedina marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) -> typing.Dict[str, typing.Any]: | ||
|
||
| """ | ||
| Converts a normal dictionary to the format used for submission annotations, which is different from the format | ||
| used to annotate entities. | ||
|
|
||
| This function creates the proper nested structure that includes id, etag, and annotations in the format | ||
| expected by the submissionAnnotations field of a SubmissionStatus request body. | ||
|
|
||
| Arguments: | ||
| id: The unique ID of the submission being annotated. | ||
| etag: The etag of the submission status for optimistic concurrency control. | ||
| annotations: A normal Python dictionary comprised of the annotations to be added. | ||
| logger: An optional logger instance. If not provided, a default logger will be used. | ||
|
|
||
| Returns: | ||
| A dictionary in the format expected by submissionAnnotations with nested structure containing | ||
| id, etag, and annotations object with type/value format. | ||
|
|
||
| Example: Using this function | ||
| Converting annotations to submission format | ||
|
|
||
| from synapseclient.annotations import to_submission_annotations | ||
|
|
||
| # Input annotations | ||
| my_annotations = { | ||
| "score": 85, | ||
| "feedback": "Good work!" | ||
| } | ||
|
|
||
| # Convert to submission annotations format | ||
| submission_annos = to_submission_annotations( | ||
| id="9999999", | ||
| etag="abc123", | ||
| annotations=my_annotations, | ||
| is_private=True | ||
| ) | ||
|
|
||
| # Result: | ||
| # { | ||
| # "id": "9999999", | ||
| # "etag": "abc123", | ||
| # "annotations": { | ||
| # "score": {"type": "INTEGER", "value": [85]}, | ||
| # "feedback": {"type": "STRING", "value": ["Good work!"]}, | ||
| # } | ||
| # } | ||
|
|
||
| Note: | ||
| This function is designed specifically for the submissionAnnotations field format, | ||
| which is part of the creation of a SubmissionStatus request body: | ||
|
|
||
| <https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/model/annotation/v2/Annotations.html> | ||
| """ | ||
| # Create the base structure | ||
| submission_annos = {"id": str(id), "etag": str(etag), "annotations": {}} | ||
|
|
||
| # Convert each annotation to the proper nested format | ||
| for key, value in annotations.items(): | ||
| # Ensure value is a list | ||
| if not isinstance(value, list): | ||
| value_list = [value] | ||
| else: | ||
| value_list = value | ||
|
|
||
| # Warn about empty annotation values and skip them | ||
| if not value_list: | ||
| if logger: | ||
| logger.warning( | ||
| f"Annotation '{key}' has an empty value list and will be skipped" | ||
| ) | ||
| else: | ||
| from synapseclient import Synapse | ||
|
|
||
| client = Synapse.get_client() | ||
| client.logger.warning( | ||
| f"Annotation '{key}' has an empty value list and will be skipped" | ||
| ) | ||
| continue | ||
jaymedina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| # Determine type based on the first element | ||
| first_element = value_list[0] | ||
|
|
||
| if isinstance(first_element, str): | ||
| submission_annos["annotations"][key] = { | ||
| "type": "STRING", | ||
| "value": value_list, | ||
| } | ||
| elif isinstance(first_element, bool): | ||
| # Convert booleans to lowercase strings | ||
| submission_annos["annotations"][key] = { | ||
| "type": "STRING", | ||
| "value": [str(v).lower() for v in value_list], | ||
| } | ||
| elif isinstance(first_element, int): | ||
| submission_annos["annotations"][key] = {"type": "LONG", "value": value_list} | ||
| elif isinstance(first_element, float): | ||
| submission_annos["annotations"][key] = { | ||
| "type": "DOUBLE", | ||
| "value": value_list, | ||
| } | ||
| elif is_date(first_element): | ||
| # Convert dates to unix timestamps | ||
| submission_annos["annotations"][key] = { | ||
| "type": "LONG", | ||
| "value": [to_unix_epoch_time(v) for v in value_list], | ||
| } | ||
| else: | ||
| # Default to string representation | ||
| submission_annos["annotations"][key] = { | ||
| "type": "STRING", | ||
| "value": [str(v) for v in value_list], | ||
| } | ||
|
|
||
| return submission_annos | ||
|
|
||
|
|
||
| # TODO: this should accept a status object and return its annotations or an empty dict if there are none | ||
| def from_submission_status_annotations(annotations) -> dict: | ||
| """ | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.