Skip to content

Commit 3690a2a

Browse files
authored
[SYNPY-1551] Tables refactor (#1151)
* Implement the table model OOP, adding support for row CRUD operations including upserts
1 parent b00099f commit 3690a2a

36 files changed

+11629
-769
lines changed

docs/css/custom.css

+4
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ div.doc-contents {
77
.md-typeset table tbody {
88
font-size: .7rem
99
}
10+
11+
.md-grid {
12+
max-width: 1700px;
13+
}

docs/reference/experimental/async/table.md

+35-7
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,39 @@ at your own risk.
1111
inherited_members: true
1212
members:
1313
- get_async
14-
- store_schema_async
15-
- store_rows_from_csv_async
16-
- delete_rows_async
17-
- query_async
14+
- store_async
1815
- delete_async
19-
- get_permissions_async
20-
- get_acl_async
21-
- set_permissions_async
16+
- query_async
17+
- query_part_mask_async
18+
- store_rows_async
19+
- upsert_rows_async
20+
- delete_rows_async
21+
- snapshot_async
22+
- delete_column
23+
- add_column
24+
- reorder_column
25+
- get_permissions
26+
- get_acl
27+
- set_permissions
28+
29+
::: synapseclient.models.Column
30+
options:
31+
members:
32+
33+
::: synapseclient.models.SchemaStorageStrategy
34+
::: synapseclient.models.ColumnExpansionStrategy
35+
36+
::: synapseclient.models.FacetType
37+
::: synapseclient.models.ColumnType
38+
::: synapseclient.models.JsonSubColumn
39+
40+
41+
::: synapseclient.models.ColumnChange
42+
::: synapseclient.models.PartialRow
43+
::: synapseclient.models.PartialRowSet
44+
::: synapseclient.models.TableSchemaChangeRequest
45+
::: synapseclient.models.AppendableRowSetRequest
46+
::: synapseclient.models.UploadToTableRequest
47+
::: synapseclient.models.TableUpdateTransaction
48+
::: synapseclient.models.CsvTableDescriptor
49+
::: synapseclient.models.mixins.table_operator.csv_to_pandas_df
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
::: synapseclient.api
3+
options:
4+
inherited_members: true
5+
members:
6+
- delete_entity

docs/reference/experimental/sync/table.md

+33-4
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,45 @@ at your own risk.
1616

1717
## API Reference
1818

19+
1920
::: synapseclient.models.Table
2021
options:
2122
inherited_members: true
2223
members:
2324
- get
24-
- store_schema
25-
- store_rows_from_csv
26-
- delete_rows
27-
- query
25+
- store
2826
- delete
27+
- query
28+
- query_part_mask
29+
- store_rows
30+
- upsert_rows
31+
- delete_rows
32+
- snapshot
33+
- delete_column
34+
- add_column
35+
- reorder_column
2936
- get_permissions
3037
- get_acl
3138
- set_permissions
39+
40+
::: synapseclient.models.Column
41+
options:
42+
members:
43+
44+
::: synapseclient.models.SchemaStorageStrategy
45+
::: synapseclient.models.ColumnExpansionStrategy
46+
47+
::: synapseclient.models.FacetType
48+
::: synapseclient.models.ColumnType
49+
::: synapseclient.models.JsonSubColumn
50+
51+
52+
::: synapseclient.models.ColumnChange
53+
::: synapseclient.models.PartialRow
54+
::: synapseclient.models.PartialRowSet
55+
::: synapseclient.models.TableSchemaChangeRequest
56+
::: synapseclient.models.AppendableRowSetRequest
57+
::: synapseclient.models.UploadToTableRequest
58+
::: synapseclient.models.TableUpdateTransaction
59+
::: synapseclient.models.CsvTableDescriptor
60+
::: synapseclient.models.mixins.table_operator.csv_to_pandas_df

docs/scripts/object_orientated_programming_poc/oop_poc_table.py

+17-23
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
from datetime import date, datetime, timedelta, timezone
1717

1818
import synapseclient
19-
from synapseclient.models import Column, ColumnType, CsvResultFormat, Row, Table
19+
from synapseclient.models import Column, ColumnType, Table
2020

2121
PROJECT_ID = "syn52948289"
22+
ROWS_TO_WRITE = 10
2223

2324
syn = synapseclient.Synapse(debug=True)
2425
syn.login()
@@ -36,15 +37,15 @@ def write_random_csv_with_data(path: str):
3637
data = {}
3738
for name, type in randomized_data_columns.items():
3839
if type == int:
39-
data[name] = [random.randint(0, 100) for _ in range(10)]
40+
data[name] = [random.randint(0, 100) for _ in range(ROWS_TO_WRITE + 1)]
4041
elif type == float:
41-
data[name] = [random.uniform(0, 100) for _ in range(10)]
42+
data[name] = [random.uniform(0, 100) for _ in range(ROWS_TO_WRITE + 1)]
4243
elif type == bool:
43-
data[name] = [bool(random.getrandbits(1)) for _ in range(10)]
44+
data[name] = [bool(random.getrandbits(1)) for _ in range(ROWS_TO_WRITE + 1)]
4445
elif type == str:
4546
data[name] = [
4647
"".join(random.choices(string.ascii_uppercase + string.digits, k=5))
47-
for _ in range(10)
48+
for _ in range(ROWS_TO_WRITE + 1)
4849
]
4950

5051
with open(path, "w", newline="", encoding="utf-8") as csvfile:
@@ -54,7 +55,7 @@ def write_random_csv_with_data(path: str):
5455
writer.writerow(data.keys())
5556

5657
# Write data
57-
for i in range(10):
58+
for i in range(ROWS_TO_WRITE + 1):
5859
writer.writerow([values[i] for values in data.values()])
5960

6061

@@ -86,13 +87,13 @@ def store_table():
8687

8788
# Creating a table ===============================================================
8889
table = Table(
89-
name="my_first_test_table",
90+
name="my_first_test_table_ksidubhgfkjsdgf",
9091
columns=columns,
9192
parent_id=PROJECT_ID,
9293
annotations=annotations_for_my_table,
9394
)
9495

95-
table = table.store_schema()
96+
table = table.store()
9697

9798
print("Table created:")
9899
print(table)
@@ -107,7 +108,7 @@ def store_table():
107108

108109
# Updating annotations on my table ===============================================
109110
copy_of_table.annotations["my_key_string"] = ["new", "values", "here"]
110-
stored_table = copy_of_table.store_schema()
111+
stored_table = copy_of_table.store()
111112
print("Table updated:")
112113
print(stored_table)
113114

@@ -116,31 +117,24 @@ def store_table():
116117
path_to_csv = os.path.join(os.path.expanduser("~/temp"), f"{name_of_csv}.csv")
117118
write_random_csv_with_data(path_to_csv)
118119

119-
csv_path = copy_of_table.store_rows_from_csv(csv_path=path_to_csv)
120+
copy_of_table.store_rows(values=path_to_csv)
120121

121-
print("Stored data to table from CSV:")
122-
print(csv_path)
122+
print("Stored data to table from CSV")
123123

124124
# Querying for data from a table =================================================
125-
destination_csv_location = os.path.expanduser("~/temp/my_query_results")
126-
127125
table_id_to_query = copy_of_table.id
128-
Table.query(
129-
query=f"SELECT * FROM {table_id_to_query}",
130-
result_format=CsvResultFormat(download_location=destination_csv_location),
131-
)
126+
dataframe_from_query = Table.query(query=f"SELECT * FROM {table_id_to_query}")
132127

133-
print(f"Created results at: {destination_csv_location}")
128+
print(f"Got results: {dataframe_from_query}")
134129

135-
# Deleting rows from a table =====================================================
136-
copy_of_table.delete_rows(rows=[Row(row_id=1)])
130+
# Deleting a row from the table =====================================================
131+
copy_of_table.delete_rows(query=f"SELECT * from {table_id_to_query} LIMIT 1")
137132

138133
# Deleting a table ===============================================================
139134
table_to_delete = Table(
140135
name="my_test_table_I_want_to_delete",
141-
columns=columns,
142136
parent_id=PROJECT_ID,
143-
).store_schema()
137+
).store()
144138

145139
table_to_delete.delete()
146140

mkdocs.yml

+3
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ nav:
8383
- Activity: reference/experimental/sync/activity.md
8484
- Team: reference/experimental/sync/team.md
8585
- UserProfile: reference/experimental/sync/user_profile.md
86+
- Functional Interfaces: reference/experimental/functional_interfaces.md
8687
- Asynchronous:
8788
- Agent: reference/experimental/async/agent.md
8889
- Project: reference/experimental/async/project.md
@@ -140,6 +141,8 @@ theme:
140141
- toc.follow
141142
- navigation.tabs
142143
- navigation.tabs.sticky
144+
- navigation.instant
145+
- navigation.instant.progress
143146

144147
extra_css:
145148
- css/custom.css

synapseclient/api/__init__.py

+6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from .entity_factory import get_from_entity_factory
2525
from .entity_services import (
2626
create_access_requirements_if_none,
27+
delete_entity,
2728
delete_entity_generated_by,
2829
get_entities_by_md5,
2930
get_entity,
@@ -46,6 +47,7 @@
4647
put_file_multipart_add,
4748
put_file_multipart_complete,
4849
)
50+
from .table_services import get_columns, post_columns
4951

5052
__all__ = [
5153
# annotations
@@ -72,6 +74,7 @@
7274
"get_entity",
7375
"put_entity",
7476
"post_entity",
77+
"delete_entity",
7578
"get_upload_destination",
7679
"get_upload_destination_location",
7780
"create_access_requirements_if_none",
@@ -93,4 +96,7 @@
9396
"get_session",
9497
"update_session",
9598
"get_trace",
99+
# columns
100+
"get_columns",
101+
"post_columns",
96102
]

synapseclient/api/entity_factory.py

+17-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
if TYPE_CHECKING:
2222
from synapseclient import Synapse
23-
from synapseclient.models import File, Folder, Project
23+
from synapseclient.models import Dataset, File, Folder, Project, Table
2424

2525

2626
async def get_from_entity_factory(
@@ -32,7 +32,7 @@ async def get_from_entity_factory(
3232
download_file: bool = True,
3333
download_location: str = None,
3434
follow_link: bool = False,
35-
entity_to_update: Union["Project", "File", "Folder"] = None,
35+
entity_to_update: Union["Project", "File", "Folder", "Table", "Dataset"] = None,
3636
*,
3737
synapse_client: Optional["Synapse"] = None,
3838
) -> Union["Project", "File", "Folder"]:
@@ -292,7 +292,7 @@ class type. This will also download the file if `download_file` is set to True.
292292
synapse_annotations=entity_bundle.get("annotations", None)
293293
)
294294

295-
from synapseclient.models import File, Folder, Project
295+
from synapseclient.models import File, Folder, Project, Table
296296

297297
if entity["concreteType"] == concrete_types.PROJECT_ENTITY:
298298
if not entity_to_update:
@@ -349,6 +349,20 @@ class type. This will also download the file if `download_file` is set to True.
349349
+ "!" * len(warning_message)
350350
+ "\n"
351351
)
352+
elif entity["concreteType"] == concrete_types.TABLE_ENTITY:
353+
if not entity_to_update:
354+
entity_to_update = Table()
355+
entity = entity_to_update.fill_from_dict(
356+
entity=entity_bundle["entity"], set_annotations=False
357+
)
358+
elif entity["concreteType"] == concrete_types.DATASET_ENTITY:
359+
if not entity_to_update:
360+
from synapseclient.models import Dataset
361+
362+
entity_to_update = Dataset()
363+
entity = entity_to_update.fill_from_dict(
364+
entity=entity_bundle["entity"], set_annotations=False
365+
)
352366
else:
353367
raise ValueError(
354368
f"Attempting to retrieve an unsupported entity type of {entity['concreteType']}."

0 commit comments

Comments
 (0)