Skip to content

Conversation

@danlu1
Copy link
Contributor

@danlu1 danlu1 commented Jun 11, 2025

Problem:

  1. WikiPage Services 2 is not implemented in the client.
  2. No asynchronous get_paginated function in client module.
  3. download_from_url and download_from_url_multi_threaded are not supporting download directly via presigned url.

Solution:

  1. Add a new Wiki2 service to Python Client
  2. Add rest_get_paginated_async function to client module.
  3. Update download_from_url and download_from_url_multi_threaded functions to allow file download directly via presigned url.

Testing:

Integration tests and unit tests are added to both asynchronous and synchronous models.

@danlu1 danlu1 requested a review from a team as a code owner June 11, 2025 20:55
@danlu1 danlu1 marked this pull request as draft June 11, 2025 20:56
@danlu1
Copy link
Contributor Author

danlu1 commented Jun 11, 2025

@BryanFauble @thomasyu888 I put this draft PR to show tentative interface of the wiki2 service. Protocol, tutorials and test scripts are wip. Feel free to leave comments if you envision it differently.

@BryanFauble
Copy link
Member

Copy link
Member

@BryanFauble BryanFauble left a comment

Choose a reason for hiding this comment

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

This is a great start to the changes!

Feel free to reach out to me with questions, and re-request review when you'd like me to take a look at this PR again.

@danlu1 danlu1 changed the title [SYNPY-1351] Implement 'Wiki2' model into OOP [SYNPY-1351, SYNPY-1613] Implement 'Wiki2' model into OOP Jun 13, 2025
Comment on lines 85 to 99
Example: Get the WikiOrderHint for a project
This example shows how to get a WikiOrderHint for existing wiki pages in a project.
from synapseclient import Synapse
from synapseclient.models import (
Project,
WikiOrderHint,
)
syn = Synapse()
syn.login()
project = Project(name="My uniquely named project about Alzheimer's Disease").get()
# get the WikiOrderHint for the project
wiki_order_hint = WikiOrderHint(owner_id=project.id).get()
print(wiki_order_hint)
Copy link
Member

Choose a reason for hiding this comment

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

The formatting of every example that you've added is a bit broken:

Image
Suggested change
Example: Get the WikiOrderHint for a project
This example shows how to get a WikiOrderHint for existing wiki pages in a project.
from synapseclient import Synapse
from synapseclient.models import (
Project,
WikiOrderHint,
)
syn = Synapse()
syn.login()
project = Project(name="My uniquely named project about Alzheimer's Disease").get()
# get the WikiOrderHint for the project
wiki_order_hint = WikiOrderHint(owner_id=project.id).get()
print(wiki_order_hint)
Example: Get the WikiOrderHint for a project
This example shows how to get a WikiOrderHint for existing wiki pages in a project.
```python
from synapseclient import Synapse
from synapseclient.models import (
Project,
WikiOrderHint,
)
syn = Synapse()
syn.login()
project = Project(name="My uniquely named project about Alzheimer's Disease").get()
# get the WikiOrderHint for the project
wiki_order_hint = WikiOrderHint(owner_id=project.id).get()
print(wiki_order_hint)
```

The code needs to be wrapped in backticks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do. @BryanFauble qq. how can I render the docs locally?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm working on formatting the docs.

Comment on lines 248 to 290
@classmethod
@otel_trace_method(
method_to_trace_name=lambda self, **kwargs: f"Get_Wiki_History for Owner ID {kwargs['owner_id']}, Wiki ID {kwargs['id']}"
)
async def get_async(
cls,
owner_id: str = None,
id: str = None,
*,
offset: int = 0,
limit: int = 20,
synapse_client: Optional["Synapse"] = None,
) -> List["WikiHistorySnapshot"]:
"""
Get the history of a wiki page as a list of WikiHistorySnapshot objects.
Arguments:
owner_id: The Synapse ID of the owner entity.
id: The ID of the wiki page.
offset: The index of the pagination offset.
limit: Limits the size of the page returned.
synapse_client: Optionally provide a Synapse client.
Returns:
A list of WikiHistorySnapshot objects for the wiki page.
Example: Get the history of a wiki page
history = await WikiHistorySnapshot.get_async(owner_id=project.id, id=wiki_page.id)
print(f"History: {history}")
"""
if not owner_id:
raise ValueError("Must provide owner_id to get wiki history.")
if not id:
raise ValueError("Must provide id to get wiki history.")
snapshots = []
async for item in get_wiki_history(
owner_id=owner_id,
wiki_id=id, # use id instead of wiki_id to match other classes
offset=offset,
limit=limit,
synapse_client=synapse_client,
):
snapshots.append(cls().fill_from_dict(item))
return snapshots
Copy link
Member

Choose a reason for hiding this comment

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

Are there cases where this could return hundreds/thousands of results?

If there is I would consider swapping this to be a generator instead of getting all results.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It depends on how many versions a wiki page can have. I will tweak it.

Comment on lines 666 to 669
not attachment.endswith(".gz")
and not attachment.endswith(".png")
and not attachment.endswith(".jpg")
and not attachment.endswith(".jpeg")
Copy link
Member

Choose a reason for hiding this comment

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

Is there a list of these somewhere, or is this derived from documentation on the rest-docs? I am curious if there are additional image formats to add here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a list I found online, and I couldn’t find corresponding documentation in the REST docs. I added because I noticed that images are handled differently from other file types.

markdown=wiki_markdown,
)
root_wiki = await wiki_page.store_async(synapse_client=syn)
schedule_for_cleanup(root_wiki.id)
Copy link
Member

Choose a reason for hiding this comment

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

Does this work? I know I had to add some specific logic for a few class types to work properly with the clean function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don’t think so. Some of the integration tests failed in CI/CD, and the number of wiki pages differs from what I see when running the async and sync tests separately on my local.

Copy link
Contributor Author

@danlu1 danlu1 Dec 30, 2025

Choose a reason for hiding this comment

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

I forced the root wiki to be deleted in each test script to leave an empty canvas for the next test. And also made changes to the schedule_for_cleanup to take care of wiki related objects.

assert os.path.exists(downloaded_path)
assert os.path.basename(downloaded_path) == "preview.txt"

@pytest.mark.skipif(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function was found online to skip the test in CI/CD envs and it seems to work.
Screenshot 2025-12-29 at 10 15 29 AM

Copy link
Member

@BryanFauble BryanFauble left a comment

Choose a reason for hiding this comment

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

Thank you for this round. There are a few things to patch up, but this is in a great place

@danlu1 danlu1 requested a review from BryanFauble December 30, 2025 22:24
Copy link
Member

@BryanFauble BryanFauble left a comment

Choose a reason for hiding this comment

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

Thanks for your hard work on this. It looks good to me!

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.

4 participants