Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ jobs:
needs: [pre-commit]

strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, macos-13, windows-2022]

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ coverage.xml
.ipynb_checkpoints
*.ipynb
.env
test.synapseConfig
30 changes: 30 additions & 0 deletions docs/reference/experimental/async/factory_operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Synapse Factory Operations

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

[](){ #factory-get-async }
::: synapseclient.operations.get_async

[](){ #factory-file-options-async }
::: synapseclient.operations.FileOptions
options:
inherited_members: true

[](){ #factory-activity-options-async }
::: synapseclient.operations.ActivityOptions
options:
inherited_members: true

[](){ #factory-table-options-async }
::: synapseclient.operations.TableOptions
options:
inherited_members: true

[](){ #factory-link-options-async }
::: synapseclient.operations.LinkOptions
options:
inherited_members: true
16 changes: 16 additions & 0 deletions docs/reference/experimental/async/link_entity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[](){ #link-async }
# Link

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.Link
options:
inherited_members: true
members:
- get_async
- store_async
---
30 changes: 30 additions & 0 deletions docs/reference/experimental/sync/factory_operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Synapse Factory Operations

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

[](){ #factory-get-sync }
::: synapseclient.operations.get

[](){ #factory-file-options-sync }
::: synapseclient.operations.FileOptions
options:
inherited_members: true

[](){ #factory-activity-options-sync }
::: synapseclient.operations.ActivityOptions
options:
inherited_members: true

[](){ #factory-table-options-sync }
::: synapseclient.operations.TableOptions
options:
inherited_members: true

[](){ #factory-link-options-sync }
::: synapseclient.operations.LinkOptions
options:
inherited_members: true
16 changes: 16 additions & 0 deletions docs/reference/experimental/sync/link_entity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[](){ #link-sync }
# Link

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.Link
options:
inherited_members: true
members:
- get
- store
---
4 changes: 4 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ nav:
- Core: reference/core.md
- REST Apis: reference/rest_apis.md
- Experimental:
- Factory Operations: reference/experimental/sync/factory_operations.md
- Agent: reference/experimental/sync/agent.md
- Project: reference/experimental/sync/project.md
- Folder: reference/experimental/sync/folder.md
Expand All @@ -94,8 +95,10 @@ nav:
- Activity: reference/experimental/sync/activity.md
- Team: reference/experimental/sync/team.md
- UserProfile: reference/experimental/sync/user_profile.md
- Link: reference/experimental/sync/link_entity.md
- Functional Interfaces: reference/experimental/functional_interfaces.md
- Asynchronous:
- Factory Operations: reference/experimental/async/factory_operations.md
- Agent: reference/experimental/async/agent.md
- Project: reference/experimental/async/project.md
- Folder: reference/experimental/async/folder.md
Expand All @@ -110,6 +113,7 @@ nav:
- Activity: reference/experimental/async/activity.md
- Team: reference/experimental/async/team.md
- UserProfile: reference/experimental/async/user_profile.md
- Link: reference/experimental/async/link_entity.md
- Mixins:
- AccessControllable: reference/experimental/mixins/access_controllable.md
- StorableContainer: reference/experimental/mixins/storable_container.md
Expand Down
2 changes: 2 additions & 0 deletions synapseclient/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
delete_entity_generated_by,
delete_entity_provenance,
get_activity,
get_child,
get_children,
get_entities_by_md5,
get_entity,
Expand Down Expand Up @@ -167,6 +168,7 @@
"get_activity",
"create_activity",
"update_activity",
"get_child",
"get_children",
"post_entity_acl",
"put_entity_acl",
Expand Down
2 changes: 2 additions & 0 deletions synapseclient/api/entity_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ class type. This will also download the file if `download_file` is set to True.
EntityView,
File,
Folder,
Link,
MaterializedView,
Project,
SubmissionView,
Expand Down Expand Up @@ -377,6 +378,7 @@ class type. This will also download the file if `download_file` is set to True.
concrete_types.MATERIALIZED_VIEW: MaterializedView,
concrete_types.SUBMISSION_VIEW: SubmissionView,
concrete_types.VIRTUAL_TABLE: VirtualTable,
concrete_types.LINK_ENTITY: Link,
}

entity_class = ENTITY_TYPE_MAP.get(entity["concreteType"], None)
Expand Down
93 changes: 93 additions & 0 deletions synapseclient/api/entity_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,99 @@ async def main():
yield child


async def get_child(
entity_name: str,
parent_id: Optional[str] = None,
*,
synapse_client: Optional["Synapse"] = None,
) -> Optional[str]:
"""
Retrieve an entityId for a given parent ID and entity name.

This service can also be used to lookup projectId by setting the parentId to None.

This calls to the REST API found here: <https://rest-docs.synapse.org/rest/POST/entity/child.html>

Arguments:
entity_name: The name of the entity to find
parent_id: The parent ID. Set to None when looking up a project by name.
synapse_client: If not passed in and caching was not disabled by
`Synapse.allow_client_caching(False)` this will use the last created
instance from the Synapse class constructor.

Returns:
The entity ID if found, None if not found.

Raises:
SynapseHTTPError: If there's an error other than "not found" (404).

Example: Getting a child entity ID
Find a file by name within a folder:

```python
import asyncio
from synapseclient import Synapse
from synapseclient.api import get_child

syn = Synapse()
syn.login()

async def main():
entity_id = await get_child(
entity_name="my_file.txt",
parent_id="syn123456"
)
if entity_id:
print(f"Found entity: {entity_id}")
else:
print("Entity not found")

asyncio.run(main())
```

Example: Getting a project by name
Find a project by name:

```python
import asyncio
from synapseclient import Synapse
from synapseclient.api import get_child

syn = Synapse()
syn.login()

async def main():
project_id = await get_child(
entity_name="My Project",
parent_id=None # None for projects
)
if project_id:
print(f"Found project: {project_id}")

asyncio.run(main())
```
"""
from synapseclient import Synapse

client = Synapse.get_client(synapse_client=synapse_client)

entity_lookup_request = {
"parentId": parent_id,
"entityName": entity_name,
}

try:
response = await client.rest_post_async(
uri="/entity/child", body=json.dumps(entity_lookup_request)
)
return response.get("id")
except SynapseHTTPError as e:
if e.response.status_code == 404:
# Entity not found
return None
raise


async def set_entity_permissions(
entity_id: str,
principal_id: Optional[str] = None,
Expand Down
27 changes: 9 additions & 18 deletions synapseclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2042,8 +2042,7 @@ def _getWithEntityBundle(
if_collision=ifcollision,
submission=submission,
synapse_client=self,
),
syn=self,
)
)
else: # no filehandle means that we do not have DOWNLOAD permission
warning_message = (
Expand Down Expand Up @@ -2452,8 +2451,7 @@ def store(
md5=local_file_md5_hex or local_state_fh.get("contentMd5"),
file_size=local_state_fh.get("contentSize"),
mimetype=local_state_fh.get("contentType"),
),
self,
)
)
properties["dataFileHandleId"] = fileHandle["id"]
local_state["_file_handle"] = fileHandle
Expand Down Expand Up @@ -2911,8 +2909,7 @@ async def upload_file():
return wrap_async_to_sync(
upload_file_handle_async(
self, parent, path, synapseStore, md5, file_size, mimetype
),
self,
)
)

############################################################
Expand Down Expand Up @@ -6797,8 +6794,7 @@ def getWiki(self, owner, subpageId=None, version=None):
cache_dir, str(wiki.markdownFileHandleId) + ".md"
),
synapse_client=self,
),
syn=self,
)
)
try:
import gzip
Expand Down Expand Up @@ -6849,9 +6845,7 @@ def _storeWiki(self, wiki: Wiki, createOrUpdate: bool) -> Wiki:
# Convert all attachments into file handles
if wiki.get("attachments") is not None:
for attachment in wiki["attachments"]:
fileHandle = wrap_async_to_sync(
upload_synapse_s3(self, attachment), self
)
fileHandle = wrap_async_to_sync(upload_synapse_s3(self, attachment))
wiki["attachmentFileHandleIds"].append(fileHandle["id"])
del wiki["attachments"]

Expand Down Expand Up @@ -7800,7 +7794,7 @@ async def upload_csv_with_chunk_method(table_id, path):
"""

fileHandleId = wrap_async_to_sync(
multipart_upload_file_async(self, filepath, content_type="text/csv"), self
multipart_upload_file_async(self, filepath, content_type="text/csv")
)

uploadRequest = {
Expand Down Expand Up @@ -8009,8 +8003,7 @@ async def async_csv_download():
entity_type="TableEntity",
destination=os.path.join(download_dir, filename),
synapse_client=self,
),
syn=self,
)
)

return download_from_table_result, path
Expand Down Expand Up @@ -8310,8 +8303,7 @@ def downloadTableColumns(self, table, columns, downloadLocation=None, **kwargs):
synapse_id=table.tableId,
entity_type="TableEntity",
destination=zipfilepath,
),
syn=self,
)
)
# TODO handle case when no zip file is returned
# TODO test case when we give it partial or all bad file handles
Expand Down Expand Up @@ -8578,8 +8570,7 @@ def sendMessage(
"""

fileHandleId = wrap_async_to_sync(
multipart_upload_string_async(self, messageBody, content_type=contentType),
self,
multipart_upload_string_async(self, messageBody, content_type=contentType)
)
message = dict(
recipients=userIds, subject=messageSubject, fileHandleId=fileHandleId
Expand Down
7 changes: 2 additions & 5 deletions synapseclient/core/async_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@

import asyncio
import functools
from typing import TYPE_CHECKING, Any, Callable, Coroutine, Union
from typing import Any, Callable, Coroutine, Union

import nest_asyncio
from opentelemetry import trace

if TYPE_CHECKING:
from synapseclient import Synapse

tracer = trace.get_tracer("synapseclient")


Expand Down Expand Up @@ -77,7 +74,7 @@ def f(*args, **kwds):
return f


def wrap_async_to_sync(coroutine: Coroutine[Any, Any, Any], syn: "Synapse") -> Any:
def wrap_async_to_sync(coroutine: Coroutine[Any, Any, Any]) -> Any:
"""Wrap an async function to be called in a sync context."""
loop = None

Expand Down
3 changes: 1 addition & 2 deletions synapseclient/core/upload/multipart_upload_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,7 @@ def _refresh_pre_signed_part_urls(
self._fetch_pre_signed_part_urls_async(
self._upload_id,
list(self._pre_signed_part_urls.keys()),
),
syn=self._syn,
)
)

refreshed_url = self._pre_signed_part_urls[part_number]
Expand Down
Loading
Loading