Skip to content

[SYNPY-1577] Submission View #1192

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

Merged
merged 43 commits into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a084116
adds initial DatasetCollection implementation
BWMac Apr 10, 2025
2d4b8e6
adds unit tests
BWMac Apr 10, 2025
3d14cd7
pre-commit
BWMac Apr 10, 2025
cd9e910
updates docstrings
BWMac Apr 10, 2025
e1a1e8a
adds integration tests
BWMac Apr 11, 2025
41eaf74
adds docs pages
BWMac Apr 11, 2025
25f12ff
removes example script section from dataset documentation
BWMac Apr 11, 2025
3a5b017
adds dataset collection tutorial
BWMac Apr 11, 2025
2ffdeab
fixes tutorial script
BWMac Apr 11, 2025
c43a172
adds tutorial path to mkdocs.yml
BWMac Apr 11, 2025
0b40a21
bullet points
BWMac Apr 11, 2025
73baab0
fixes tutorial code lines
BWMac Apr 11, 2025
9d2984e
fixes tutorial references
BWMac Apr 11, 2025
c4866f6
test doc format fix
BWMac Apr 14, 2025
6c196a3
fixes dataset docs
BWMac Apr 14, 2025
daedf46
fixes sync integration tests
BWMac Apr 14, 2025
84a73e3
fixes DatasetCollection docstrings
BWMac Apr 14, 2025
60fa4f7
refactors entity factory
BWMac Apr 14, 2025
cd208d6
fixes argument error
BWMac Apr 14, 2025
3a70496
updates test strings
BWMac Apr 14, 2025
b7e728e
Merge branch 'develop' into synpy-1578-oop-model-dataset-collection
BWMac Apr 14, 2025
7512c0e
pre-commit
BWMac Apr 14, 2025
e0e82bd
Update docs/tutorials/python/dataset_collection.md
BWMac Apr 15, 2025
27a7656
updates tutorials
BWMac Apr 15, 2025
cd775a5
removes elif block
BWMac Apr 15, 2025
0b2603f
pre-commit
BWMac Apr 15, 2025
66c562a
removes unused cleanup
BWMac Apr 15, 2025
87950e9
updates version handling and tests
BWMac Apr 15, 2025
1368c7a
fix async tests
BWMac Apr 15, 2025
5d39a79
addresses comments
BWMac Apr 15, 2025
f279036
fixes docstrings
BWMac Apr 15, 2025
d63b212
adds retry logic for uncaught async jobs
BWMac Apr 15, 2025
345a2ee
set max on timeout
BWMac Apr 15, 2025
7a993ba
addresses comments
BWMac Apr 15, 2025
fe17606
updates unit test for version num
BWMac Apr 16, 2025
80edc7e
fixes incorrect line number
BWMac Apr 16, 2025
6bc4374
adds missing snapshot tests
BWMac Apr 16, 2025
f646dc1
corrects type hint
BWMac Apr 16, 2025
e16ab00
submission-view
BryanFauble Apr 17, 2025
5a7b83f
Adds a new SubmissionView model class that represents Synapse Submiss…
BryanFauble Apr 17, 2025
d3e833a
Update ranking for sync apir reference on mkdocs
BryanFauble Apr 17, 2025
8ce19b8
Update tutorial as first query won't have updated data
BryanFauble Apr 17, 2025
d04d603
removal of the redundant has_columns_changed property method from mul…
BryanFauble Apr 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ python:
# See https://docs.readthedocs.com/platform/stable/config-file/v2.html#search for more options
search:
ranking:
reference/*: -1
reference/*: -3
reference/experimental/*: -2
reference/experimental/sync/*: -1
25 changes: 25 additions & 0 deletions docs/reference/experimental/async/submissionview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SubmissionView

Contained within this file are experimental interfaces for working with the Synapse Python
Client. Unless otherwise noted these interfaces are subject to change at any time. Use
at your own risk.

## API reference

::: synapseclient.models.SubmissionView
options:
inherited_members: true
members:
- store_async
- get_async
- delete_async
- query_async
- query_part_mask_async
- snapshot_async
- add_column
- reorder_column
- delete_column
- get_acl_async
- get_permissions_async
- set_permissions_async
---
25 changes: 25 additions & 0 deletions docs/reference/experimental/sync/submissionview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SubmissionView

Contained within this file are experimental interfaces for working with the Synapse Python
Client. Unless otherwise noted these interfaces are subject to change at any time. Use
at your own risk.

## API reference

::: synapseclient.models.SubmissionView
options:
inherited_members: true
members:
- store
- get
- delete
- query
- query_part_mask
- snapshot
- add_column
- reorder_column
- delete_column
- get_acl
- get_permissions
- set_permissions
---
1 change: 1 addition & 0 deletions docs/tutorials/python/dataset.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,4 @@ Finally, let's save a snapshot of the dataset. This creates a read-only version
- [Column][synapseclient.models.Column]
- [syn.login][synapseclient.Synapse.login]
- [Project](../../reference/experimental/sync/project.md)
- [query examples](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/web/controller/TableExamples.html)
1 change: 1 addition & 0 deletions docs/tutorials/python/entityview.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,4 @@ Synapse web UI. It should look similar to:
- [Column][synapseclient.models.Column]
- [syn.login][synapseclient.Synapse.login]
- [Project](../../reference/experimental/sync/project.md)
- [query examples](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/web/controller/TableExamples.html)
1 change: 1 addition & 0 deletions docs/tutorials/python/materializedview.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,4 @@ Results from the materialized view with UNION:
- [Column][synapseclient.models.Column]
- [Project][synapseclient.models.Project]
- [syn.login][synapseclient.Synapse.login]
- [query examples](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/web/controller/TableExamples.html)
133 changes: 133 additions & 0 deletions docs/tutorials/python/submissionview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# SubmissionView

SubmissionViews in Synapse allow you to aggregate and query submissions from one or more
evaluation queues in a tabular format. These views are useful for managing submissions in
challenges, tracking scoring progress, and analyzing submission data across different
evaluation queues.

This tutorial will walk you through the basics of working with SubmissionViews
using the Synapse Python client.

## Tutorial Purpose
In this tutorial, you will:

1. Set up and create an evaluation queue
2. Create a SubmissionView for the evaluation queue
3. Create and submit a file to the evaluation queue
4. Query and update the submission status
5. Modify the SubmissionView scope
6. Create a snapshot of the view
7. Query the snapshot

## Prerequisites
* This tutorial assumes that you have a Synapse project.
* Pandas must also be installed as shown in the [installation documentation](../installation.md).

## 1. Set up and create an evaluation queue

Before creating a SubmissionView, we need to log in to Synapse, retrieve your project,
and create an evaluation queue that will be used in the view.

You will want to replace `"My uniquely named project about Alzheimer's Disease"` with
the name of your project.

```python
{!docs/tutorials/python/tutorial_scripts/submissionview.py!lines=13-44}
```

## 2. Create a SubmissionView for the evaluation queue

Next, we will create a SubmissionView that includes the evaluation queue we just created
in its scope. We'll also add custom columns for metrics that will be used for scoring
submissions.

```python
{!docs/tutorials/python/tutorial_scripts/submissionview.py!lines=46-82}
```

## 3. Create and submit a file to the evaluation queue

Now let's create a test file and submit it to our evaluation queue. For convenience,
we'll use a temporary file that will be automatically cleaned up after execution.

```python
{!docs/tutorials/python/tutorial_scripts/submissionview.py!lines=84-105}
```

## 4. Query and update the submission status

After submitting a file, we can query the SubmissionView to see our submission and update
its status with scoring metrics.

Note: Due to Synapse's eventual consistency model, we need to wait briefly for the
submission to appear in the view.

```python
{!docs/tutorials/python/tutorial_scripts/submissionview.py!lines=107-126}
```

<details class="example">
<summary>The result of querying your SubmissionView should include your submission with its details:</summary>
```
Query results:
ROW_ID ROW_VERSION ROW_ETAG metric_A metric_B ... submitteralias entityid entityversion dockerrepositoryname dockerdigest
0 9751779 0 e7c37ec7-e5e8-435d-b378-dc2d6bddad21 NaN NaN ... Participant 1 syn66272627 1 NaN NaN
```

After updating the submission status:

```
Submission status: SCORED
```
</details>

## 5. Modify the SubmissionView scope

As your challenge evolves, you might need to add more evaluation queues to your SubmissionView.
Here's how to create another evaluation queue and add it to your view's scope.

```python
{!docs/tutorials/python/tutorial_scripts/submissionview.py!lines=128-143}
```

## 6. Create a snapshot of the view

SubmissionViews support creating snapshots, which capture the state of all submissions at a
specific point in time. This is useful for archiving or comparing submission states.

```python
{!docs/tutorials/python/tutorial_scripts/submissionview.py!lines=145-152}
```

## 7. Query the snapshot

After creating a snapshot, you can query it to retrieve the state of submissions at the
time the snapshot was created. This is useful for historical analysis or auditing.

```python
{!docs/tutorials/python/tutorial_scripts/submissionview.py!lines=153-162}
```

## Source Code for this Tutorial

<details class="quote">
<summary>Click to show me</summary>

```python
{!docs/tutorials/python/tutorial_scripts/submissionview.py!}
```
</details>

## References
- [SubmissionView][synapseclient.models.SubmissionView]
- [Evaluation][synapseclient.evaluation]
- [syn.submit][synapseclient.Synapse.submit]
- [syn.getSubmissionStatus][synapseclient.Synapse.getSubmissionStatus]
- [syn.getSubmission][synapseclient.Synapse.getSubmission]
- [syn.getSubmissions][synapseclient.Synapse.getSubmissions]
- [syn.getSubmissionBundles][synapseclient.Synapse.getSubmissionBundles]
- [syn.store][synapseclient.Synapse.store]
- [Column][synapseclient.models.Column]
- [Project][synapseclient.models.Project]
- [syn.login][synapseclient.Synapse.login]
- [query examples](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/web/controller/TableExamples.html)
162 changes: 162 additions & 0 deletions docs/tutorials/python/tutorial_scripts/submissionview.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
"""
Here is where you'll find the code for the SubmissionView tutorial.

A SubmissionView allows you to aggregate and query submissions from one or more
evaluation queues in a tabular format, similar to other view types in Synapse.

This tutorial also shows how to create an evaluation queue, submit a file to it, and
update the submission status. The example uses a temporary file for the submission,
which is automatically cleaned up after the script runs. You can modify the file
path and name as needed.

"""

import tempfile

import pandas as pd

from synapseclient import Evaluation, Synapse
from synapseclient.models import (
Activity,
Column,
ColumnType,
File,
Project,
SubmissionView,
UsedURL,
)

syn = Synapse()
syn.login()

# Retrieve the project ID
my_project = Project(name="My uniquely named project about Alzheimer's Disease").get()
project_id = my_project.id
print(f"My project ID is: {project_id}")

# Step 1: Set up and create an evaluation queue
evaluation_name = "Test Evaluation Queue for Alzheimer conference"
evaluation_description = "Evaluation queue for testing submission view"
evaluation = Evaluation(
name=evaluation_name, description=evaluation_description, contentSource=project_id
)
evaluation = syn.store(evaluation)
print(f"Created evaluation queue with ID: {evaluation.id}")

# Step 2: Create a SubmissionView for the evaluation queue
view = SubmissionView(
name="SubmissionView for Alzheimer conference",
parent_id=project_id,
scope_ids=[evaluation.id],
include_default_columns=True,
columns=[
Column(
name="metric_A",
column_type=ColumnType.DOUBLE,
),
Column(
name="metric_B",
column_type=ColumnType.DOUBLE,
),
],
activity=Activity(
name="Submission Review Analysis",
description="Analysis of Q1 2025 challenge submissions",
used=[
UsedURL(
name="Challenge Homepage",
url="https://sagebionetworks.org/community/challenges-portal",
)
],
),
).store()

print(f"My SubmissionView ID is: {view.id}")

# Reorder columns for better display
view.reorder_column(name="name", index=2)
view.reorder_column(name="status", index=3)
view.reorder_column(name="evaluationid", index=4)
view.store()

print("Available columns in the view:", list(view.columns.keys()))

# Step 3: Create and submit a file to the evaluation queue
with tempfile.NamedTemporaryFile(
mode="w", suffix=".txt", delete=True, delete_on_close=False
Copy link
Preview

Copilot AI Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of both 'delete' and 'delete_on_close' parameters in NamedTemporaryFile is non-standard and may lead to unexpected behavior; consider using only one appropriate parameter based on your intended file deletion behavior.

Suggested change
mode="w", suffix=".txt", delete=True, delete_on_close=False
mode="w", suffix=".txt", delete=True

Copilot uses AI. Check for mistakes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad suggestion. Using both means the file is deleted when leaving the content managed "with" statement, but not deleted the moment we stop writing to the file through I/O

) as temp_file:
with open(temp_file.name, "w") as opened_temp_file:
opened_temp_file.write("This is a test submission file.")
temp_file_path = temp_file.name

# Upload the temporary file to Synapse
submission_file = File(
path=temp_file_path, parent_id=project_id, name="Test Submission"
).store()

# Submit the file to the evaluation queue
submission = syn.submit(
evaluation=evaluation,
entity=submission_file,
name="Test Submission",
submitterAlias="Participant 1",
)

print(f"Created submission with ID: {submission.id}")

# Step 4: Query and update the submission status
# Query the SubmissionView to see our submission
query = f"SELECT * FROM {view.id} WHERE id = '{submission.id}'"
results_as_dataframe: pd.DataFrame = view.query(query=query)
# Due to the eventual consistency of the system, we need to perform 2 queries
results_as_dataframe: pd.DataFrame = view.query(query=query)

print("Query results:")
print(results_as_dataframe)

# Update the status to indicate it's been scored
submission_status = syn.getSubmissionStatus(submission=submission.id)
print(f"Submission status: {submission_status.status}")
submission_status.status = "SCORED"
submission_status.submissionAnnotations["metric_A"] = 90
submission_status.submissionAnnotations["metric_B"] = 80
submission_status.score = 0.7
submission_status = syn.store(submission_status)
print(f"Updated submission status to: {submission_status.status}")

# Step 5: Modify the SubmissionView scope
# First let's make sure we have the latest view from Synapse:
view.get()

# Create another evaluation queue to demonstrate adding to the scope
second_evaluation = Evaluation(
name="Second Test Evaluation Queue for Alzheimer conference",
description="Another evaluation queue for testing submission view",
contentSource=project_id,
)
second_evaluation = syn.store(second_evaluation)
print(f"Created second evaluation queue with ID: {second_evaluation.id}")

# Add the new evaluation queue to the view's scope
view.scope_ids.append(second_evaluation.id)
view.store() # Store the updated view
print("Updated SubmissionView scope. Current scope IDs:", view.scope_ids)

# Step 6: Create a snapshot of the view
snapshot_info = view.snapshot(
comment="Initial submission review snapshot",
)
print("Created snapshot of the SubmissionView:")
print(snapshot_info)
snapshot_version = snapshot_info.snapshot_version_number
print(f"Snapshot version number: {snapshot_version}")

# Step 7: Query the snapshot we just created
# You may also get the snapshot version from the view object directly by looking at the version number
# (which is the latest version of the view) and subtracting 1.
# snapshot_version = view.version_number - 1

snapshot_query = f"SELECT * FROM {view.id}.{snapshot_version}"
snapshot_results = view.query(snapshot_query)
print("Query results from the snapshot:")
print(snapshot_results)
3 changes: 3 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ nav:
- Dataset: tutorials/python/dataset.md
- Dataset Collection: tutorials/python/dataset_collection.md
- Materialized View: tutorials/python/materializedview.md
- Submission View: tutorials/python/submissionview.md
# - Sharing Settings: tutorials/python/sharing_settings.md
# - Wiki: tutorials/python/wiki.md
# - Team: tutorials/python/team.md
Expand Down Expand Up @@ -86,6 +87,7 @@ nav:
- Dataset Collection: reference/experimental/sync/dataset_collection.md
- EntityView: reference/experimental/sync/entityview.md
- MaterializedView: reference/experimental/sync/materializedview.md
- SubmissionView: reference/experimental/sync/submissionview.md
- Activity: reference/experimental/sync/activity.md
- Team: reference/experimental/sync/team.md
- UserProfile: reference/experimental/sync/user_profile.md
Expand All @@ -100,6 +102,7 @@ nav:
- Dataset Collection: reference/experimental/async/dataset_collection.md
- EntityView: reference/experimental/async/entityview.md
- MaterializedView: reference/experimental/async/materializedview.md
- SubmissionView: reference/experimental/async/submissionview.md
- Activity: reference/experimental/async/activity.md
- Team: reference/experimental/async/team.md
- UserProfile: reference/experimental/async/user_profile.md
Expand Down
Loading
Loading