|
28 | 28 | from synapseclient.core.constants.concrete_types import ( |
29 | 29 | CREATE_GRID_REQUEST, |
30 | 30 | FILE_BASED_METADATA_TASK_PROPERTIES, |
| 31 | + GRID_CSV_IMPORT_REQUEST, |
31 | 32 | GRID_RECORD_SET_EXPORT_REQUEST, |
32 | 33 | LIST_GRID_SESSIONS_REQUEST, |
33 | 34 | LIST_GRID_SESSIONS_RESPONSE, |
34 | 35 | RECORD_BASED_METADATA_TASK_PROPERTIES, |
35 | 36 | ) |
| 37 | +from synapseclient.core.upload.multipart_upload_async import multipart_upload_file_async |
36 | 38 | from synapseclient.core.utils import delete_none_keys, merge_dataclass_entities |
37 | 39 | from synapseclient.models.mixins.asynchronous_job import AsynchronousCommunicator |
38 | 40 | from synapseclient.models.recordset import ValidationSummary |
@@ -1078,6 +1080,58 @@ def to_synapse_request(self) -> Dict[str, Any]: |
1078 | 1080 | return request_dict |
1079 | 1081 |
|
1080 | 1082 |
|
| 1083 | +@dataclass |
| 1084 | +class GridCsvImportRequest(AsynchronousCommunicator): |
| 1085 | + """ |
| 1086 | + A request to import a CSV file into an active grid session. |
| 1087 | +
|
| 1088 | + Represents a [Synapse GridCsvImportRequest](https://rest-docs.synapse.org/rest/org/sagebionetworks/repo/model/grid/GridCsvImportRequest.html). |
| 1089 | +
|
| 1090 | + Attributes: |
| 1091 | + concrete_type: The concrete type for the request |
| 1092 | + session_id: The grid session ID to import the CSV into |
| 1093 | + file_handle_id: The file handle ID of the CSV to import |
| 1094 | + """ |
| 1095 | + |
| 1096 | + concrete_type: str = GRID_CSV_IMPORT_REQUEST |
| 1097 | + """The concrete type for the request""" |
| 1098 | + |
| 1099 | + session_id: Optional[str] = None |
| 1100 | + """The grid session ID to import the CSV into""" |
| 1101 | + |
| 1102 | + file_handle_id: Optional[str] = None |
| 1103 | + """The file handle ID of the CSV to import""" |
| 1104 | + |
| 1105 | + def fill_from_dict( |
| 1106 | + self, synapse_response: Union[Dict[str, Any], Any] |
| 1107 | + ) -> "GridCsvImportRequest": |
| 1108 | + """ |
| 1109 | + Converts a response from the REST API into this dataclass. |
| 1110 | +
|
| 1111 | + Arguments: |
| 1112 | + synapse_response: The response from the REST API. |
| 1113 | +
|
| 1114 | + Returns: |
| 1115 | + The GridCsvImportRequest object. |
| 1116 | + """ |
| 1117 | + self.session_id = synapse_response.get("sessionId", None) |
| 1118 | + return self |
| 1119 | + |
| 1120 | + def to_synapse_request(self) -> Dict[str, Any]: |
| 1121 | + """ |
| 1122 | + Converts this dataclass to a dictionary suitable for a Synapse REST API request. |
| 1123 | +
|
| 1124 | + Returns: |
| 1125 | + A dictionary representation of this object for API requests. |
| 1126 | + """ |
| 1127 | + request_dict = {"concreteType": self.concrete_type} |
| 1128 | + if self.session_id is not None: |
| 1129 | + request_dict["sessionId"] = self.session_id |
| 1130 | + if self.file_handle_id is not None: |
| 1131 | + request_dict["fileHandleId"] = self.file_handle_id |
| 1132 | + return request_dict |
| 1133 | + |
| 1134 | + |
1081 | 1135 | @dataclass |
1082 | 1136 | class GridSession: |
1083 | 1137 | """ |
@@ -1373,6 +1427,70 @@ def delete(self, *, synapse_client: Optional[Synapse] = None) -> None: |
1373 | 1427 | """ |
1374 | 1428 | return None |
1375 | 1429 |
|
| 1430 | + def import_csv( |
| 1431 | + self, |
| 1432 | + file_handle_id: Optional[str] = None, |
| 1433 | + path: Optional[str] = None, |
| 1434 | + *, |
| 1435 | + timeout: int = 120, |
| 1436 | + synapse_client: Optional[Synapse] = None, |
| 1437 | + ) -> "Grid": |
| 1438 | + """ |
| 1439 | + Import a CSV file into the active grid session. |
| 1440 | +
|
| 1441 | + Either `file_handle_id` or `path` must be provided. If `path` is provided, |
| 1442 | + the file will be uploaded via multipart upload and the resulting file handle |
| 1443 | + ID will be used. |
| 1444 | +
|
| 1445 | + Arguments: |
| 1446 | + file_handle_id: The file handle ID of the CSV to import. |
| 1447 | + Mutually exclusive with `path`. |
| 1448 | + path: Local path to a CSV file to upload and import. |
| 1449 | + Mutually exclusive with `file_handle_id`. |
| 1450 | + timeout: The number of seconds to wait for the job to complete or |
| 1451 | + progress before raising a SynapseTimeoutError. Defaults to 120. |
| 1452 | + synapse_client: If not passed in and caching was not disabled by |
| 1453 | + `Synapse.allow_client_caching(False)` this will use the last created |
| 1454 | + instance from the Synapse class constructor. |
| 1455 | +
|
| 1456 | + Returns: |
| 1457 | + Grid: This Grid instance. |
| 1458 | +
|
| 1459 | + Raises: |
| 1460 | + ValueError: If `session_id` is not set. |
| 1461 | + ValueError: If neither `file_handle_id` nor `path` is provided. |
| 1462 | + ValueError: If both `file_handle_id` and `path` are provided. |
| 1463 | +
|
| 1464 | + Example: Import a CSV by file handle ID |
| 1465 | + |
| 1466 | +
|
| 1467 | + ```python |
| 1468 | + from synapseclient import Synapse |
| 1469 | + from synapseclient.models import Grid |
| 1470 | +
|
| 1471 | + syn = Synapse() |
| 1472 | + syn.login() |
| 1473 | +
|
| 1474 | + grid = Grid(session_id="abc-123-def") |
| 1475 | + grid = grid.import_csv(file_handle_id="123456") |
| 1476 | + ``` |
| 1477 | +
|
| 1478 | + Example: Import a CSV from a local path |
| 1479 | + |
| 1480 | +
|
| 1481 | + ```python |
| 1482 | + from synapseclient import Synapse |
| 1483 | + from synapseclient.models import Grid |
| 1484 | +
|
| 1485 | + syn = Synapse() |
| 1486 | + syn.login() |
| 1487 | +
|
| 1488 | + grid = Grid(session_id="abc-123-def") |
| 1489 | + grid = grid.import_csv(path="/path/to/data.csv") |
| 1490 | + ``` |
| 1491 | + """ |
| 1492 | + return self |
| 1493 | + |
1376 | 1494 | @classmethod |
1377 | 1495 | def list( |
1378 | 1496 | cls, |
@@ -1838,3 +1956,108 @@ async def main(): |
1838 | 1956 | await delete_grid_session( |
1839 | 1957 | session_id=self.session_id, synapse_client=synapse_client |
1840 | 1958 | ) |
| 1959 | + |
| 1960 | + async def import_csv_async( |
| 1961 | + self, |
| 1962 | + file_handle_id: Optional[str] = None, |
| 1963 | + path: Optional[str] = None, |
| 1964 | + *, |
| 1965 | + timeout: int = 120, |
| 1966 | + synapse_client: Optional[Synapse] = None, |
| 1967 | + ) -> "Grid": |
| 1968 | + """ |
| 1969 | + Import a CSV file into the active grid session. |
| 1970 | +
|
| 1971 | + Either `file_handle_id` or `path` must be provided. If `path` is provided, |
| 1972 | + the file will be uploaded via multipart upload and the resulting file handle |
| 1973 | + ID will be used. |
| 1974 | +
|
| 1975 | + Arguments: |
| 1976 | + file_handle_id: The file handle ID of the CSV to import. |
| 1977 | + Mutually exclusive with `path`. |
| 1978 | + path: Local path to a CSV file to upload and import. |
| 1979 | + Mutually exclusive with `file_handle_id`. |
| 1980 | + timeout: The number of seconds to wait for the job to complete or |
| 1981 | + progress before raising a SynapseTimeoutError. Defaults to 120. |
| 1982 | + synapse_client: If not passed in and caching was not disabled by |
| 1983 | + `Synapse.allow_client_caching(False)` this will use the last created |
| 1984 | + instance from the Synapse class constructor. |
| 1985 | +
|
| 1986 | + Returns: |
| 1987 | + Grid: This Grid instance. |
| 1988 | +
|
| 1989 | + Raises: |
| 1990 | + ValueError: If `session_id` is not set. |
| 1991 | + ValueError: If neither `file_handle_id` nor `path` is provided. |
| 1992 | + ValueError: If both `file_handle_id` and `path` are provided. |
| 1993 | +
|
| 1994 | + Example: Import a CSV by file handle ID asynchronously |
| 1995 | + |
| 1996 | +
|
| 1997 | + ```python |
| 1998 | + import asyncio |
| 1999 | + from synapseclient import Synapse |
| 2000 | + from synapseclient.models import Grid |
| 2001 | +
|
| 2002 | + syn = Synapse() |
| 2003 | + syn.login() |
| 2004 | +
|
| 2005 | + async def main(): |
| 2006 | + grid = Grid(session_id="abc-123-def") |
| 2007 | + grid = await grid.import_csv_async(file_handle_id="123456") |
| 2008 | +
|
| 2009 | + asyncio.run(main()) |
| 2010 | + ``` |
| 2011 | +
|
| 2012 | + Example: Import a CSV from a local path asynchronously |
| 2013 | + |
| 2014 | +
|
| 2015 | + ```python |
| 2016 | + import asyncio |
| 2017 | + from synapseclient import Synapse |
| 2018 | + from synapseclient.models import Grid |
| 2019 | +
|
| 2020 | + syn = Synapse() |
| 2021 | + syn.login() |
| 2022 | +
|
| 2023 | + async def main(): |
| 2024 | + grid = Grid(session_id="abc-123-def") |
| 2025 | + grid = await grid.import_csv_async(path="/path/to/data.csv") |
| 2026 | +
|
| 2027 | + asyncio.run(main()) |
| 2028 | + ``` |
| 2029 | + """ |
| 2030 | + if not self.session_id: |
| 2031 | + raise ValueError("session_id is required to import a CSV into a Grid") |
| 2032 | + if file_handle_id is None and path is None: |
| 2033 | + raise ValueError( |
| 2034 | + "Either file_handle_id or path must be provided to import a CSV" |
| 2035 | + ) |
| 2036 | + if file_handle_id is not None and path is not None: |
| 2037 | + raise ValueError( |
| 2038 | + "Only one of file_handle_id or path may be provided, not both" |
| 2039 | + ) |
| 2040 | + |
| 2041 | + trace.get_current_span().set_attributes( |
| 2042 | + { |
| 2043 | + "synapse.session_id": self.session_id or "", |
| 2044 | + } |
| 2045 | + ) |
| 2046 | + |
| 2047 | + if path is not None: |
| 2048 | + client = Synapse.get_client(synapse_client=synapse_client) |
| 2049 | + file_handle_id = await multipart_upload_file_async( |
| 2050 | + syn=client, |
| 2051 | + file_path=path, |
| 2052 | + content_type="text/csv", |
| 2053 | + ) |
| 2054 | + |
| 2055 | + import_request = GridCsvImportRequest( |
| 2056 | + session_id=self.session_id, |
| 2057 | + file_handle_id=file_handle_id, |
| 2058 | + ) |
| 2059 | + await import_request.send_job_and_wait_async( |
| 2060 | + timeout=timeout, synapse_client=synapse_client |
| 2061 | + ) |
| 2062 | + |
| 2063 | + return self |
0 commit comments