Skip to content

File

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.

Example Script

Working with files
"""
Expects that ~/temp exists and is a directory.

The purpose of this script is to demonstrate how to use the new OOP interface for files.
The following actions are shown in this script:
1. Creating a file
2. Storing a file
3. Storing a file in a sub-folder
4. Renaming a file
5. Downloading a file
6. Deleting a file
7. Copying a file
8. Storing an activity to a file
9. Retrieve an activity from a file
"""

import os
from datetime import date, datetime, timedelta, timezone

import synapseclient
from synapseclient.core import utils
from synapseclient.models import Activity, File, Folder, UsedEntity, UsedURL

PROJECT_ID = "syn52948289"

syn = synapseclient.Synapse(debug=True)
syn.login()


def create_random_file(
    path: str,
) -> None:
    """Create a random file with random data.

    :param path: The path to create the file at.
    """
    with open(path, "wb") as f:
        f.write(os.urandom(1))


def store_file():
    # Cleanup synapse for previous runs - Does not delete local files/directories:
    try:
        Folder(name="file_script_folder", parent_id=PROJECT_ID).get().delete()
    except Exception:
        pass
    if not os.path.exists(os.path.expanduser("~/temp/myNewFolder")):
        os.mkdir(os.path.expanduser("~/temp/myNewFolder"))

    script_file_folder = Folder(name="file_script_folder", parent_id=PROJECT_ID).store()

    # Creating annotations for my file ==================================================
    annotations_for_my_file = {
        "my_single_key_string": "a",
        "my_key_string": ["b", "a", "c"],
        "my_key_bool": [False, False, False],
        "my_key_double": [1.2, 3.4, 5.6],
        "my_key_long": [1, 2, 3],
        "my_key_date": [date.today(), date.today() - timedelta(days=1)],
        "my_key_datetime": [
            datetime.today(),
            datetime.today() - timedelta(days=1),
            datetime.now(tz=timezone(timedelta(hours=-5))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=0))),
            datetime(2023, 12, 7, 13, 0, 0, tzinfo=timezone(timedelta(hours=-7))),
        ],
    }

    name_of_file = "file_script_my_file_with_random_data.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)

    # 1. Creating a file =================================================================
    file = File(
        path=path_to_file,
        annotations=annotations_for_my_file,
        parent_id=script_file_folder.id,
        description="This is a file with random data.",
    )

    # 2. Storing a file ==================================================================
    file = file.store()

    print(f"File created: ID: {file.id}, Parent ID: {file.parent_id}")

    name_of_file = "file_in_a_sub_folder.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)

    # 3. Storing a file to a sub-folder ==================================================
    script_sub_folder = Folder(
        name="file_script_sub_folder", parent_id=script_file_folder.id
    ).store()
    file_in_a_sub_folder = File(
        path=path_to_file,
        annotations=annotations_for_my_file,
        parent_id=script_sub_folder.id,
        description="This is a file with random data.",
    )
    file_in_a_sub_folder = file_in_a_sub_folder.store()

    print(
        f"File created in sub folder: ID: {file_in_a_sub_folder.id}, Parent ID: {file_in_a_sub_folder.parent_id}"
    )

    # 4. Renaming a file =================================================================
    name_of_file = "file_script_my_file_to_rename.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)

    # The name of the entity, and the name of the file is disjointed.
    # For example, the name of the file is "file_script_my_file_to_rename.txt"
    # and the name of the entity is "this_name_is_different"
    file: File = File(
        path=path_to_file,
        name="this_name_is_different",
        parent_id=script_file_folder.id,
    ).store()
    print(f"File created with name: {file.name}")
    print(f"The path of the file is: {file.path}")

    # You can change the name of the entity without changing the name of the file.
    file.name = "modified_name_attribute"
    file.store()
    print(f"File renamed to: {file.name}")

    # You can then change the name of the file that would be downloaded like:
    file.change_metadata(download_as="new_name_for_downloading.txt")
    print(f"File download values changed to: {file.file_handle.file_name}")

    # 5. Downloading a file ===============================================================
    # Downloading a file to a location has a default beahvior of "keep.both"
    downloaded_file = File(
        id=file.id, path=os.path.expanduser("~/temp/myNewFolder")
    ).get()
    print(f"Downloaded file: {downloaded_file.path}")

    # I can also specify how collisions are handled when downloading a file.
    # This will replace the file on disk if it already exists and is different (after).
    path_to_file = downloaded_file.path
    create_random_file(path_to_file)
    print(f"Before file md5: {utils.md5_for_file(path_to_file).hexdigest()}")
    downloaded_file = File(
        id=downloaded_file.id,
        path=os.path.expanduser("~/temp/myNewFolder"),
        if_collision="overwrite.local",
    ).get()
    print(f"After file md5: {utils.md5_for_file(path_to_file).hexdigest()}")

    # This will keep the file on disk (before), and no file is downloaded
    path_to_file = downloaded_file.path
    create_random_file(path_to_file)
    print(f"Before file md5: {utils.md5_for_file(path_to_file).hexdigest()}")
    downloaded_file = File(
        id=downloaded_file.id,
        path=os.path.expanduser("~/temp/myNewFolder"),
        if_collision="keep.local",
    ).get()
    print(f"After file md5: {utils.md5_for_file(path_to_file).hexdigest()}")

    # 6. Deleting a file =================================================================
    # Suppose I have a file that I want to delete.
    name_of_file = "file_to_delete.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)
    file_to_delete = File(path=path_to_file, parent_id=script_file_folder.id).store()
    file_to_delete.delete()

    # 7. Copying a file ===================================================================
    print(
        f"File I am going to copy: ID: {file_in_a_sub_folder.id}, Parent ID: {file_in_a_sub_folder.parent_id}"
    )
    new_sub_folder = Folder(
        name="sub_sub_folder", parent_id=script_file_folder.id
    ).store()
    copied_file_instance = file_in_a_sub_folder.copy(parent_id=new_sub_folder.id)
    print(
        f"File I copied: ID: {copied_file_instance.id}, Parent ID: {copied_file_instance.parent_id}"
    )

    # 8. Storing an activity to a file =====================================================
    activity = Activity(
        name="some_name",
        description="some_description",
        used=[
            UsedURL(name="example", url="https://www.synapse.org/"),
            UsedEntity(target_id="syn456", target_version_number=1),
        ],
        executed=[
            UsedURL(name="example", url="https://www.synapse.org/"),
            UsedEntity(target_id="syn789", target_version_number=1),
        ],
    )

    name_of_file = "file_with_an_activity.txt"
    path_to_file = os.path.join(os.path.expanduser("~/temp"), name_of_file)
    create_random_file(path_to_file)
    file_with_activity = File(
        path=path_to_file, parent_id=script_file_folder.id, activity=activity
    ).store()
    print(file_with_activity.activity)

    # 9. When I am retrieving that file later on I can get the activity like =============
    # By also specifying download_file=False, I can get the activity without downloading the file.
    new_file_with_activity_instance = File(
        id=file_with_activity.id, download_file=False
    ).get(include_activity=True)
    print(new_file_with_activity_instance.activity)


store_file()

API Reference

synapseclient.models.File dataclass

Bases: FileSynchronousProtocol, AccessControllable

A file within Synapse.

ATTRIBUTE DESCRIPTION
id

The unique immutable ID for this file. A new ID will be generated for new Files. Once issued, this ID is guaranteed to never change or be re-issued.

TYPE: Optional[str]

name

The name of this entity. Must be 256 characters or less. Names may only contain: letters, numbers, spaces, underscores, hyphens, periods, plus signs, apostrophes, and parentheses. If not specified, the name will be derived from the file name.

TYPE: Optional[str]

path

The path to the file on disk. Using shorthand ~ will be expanded to the user's home directory.

This is used during a get operation to specify where to download the file to. It should be pointing to a directory.

This is also used during a store operation to specify the file to upload. It should be pointing to a file.

TYPE: Optional[str]

description

The description of this file. Must be 1000 characters or less.

TYPE: Optional[str]

parent_id

The ID of the Entity that is the parent of this Entity. Setting this to a new value and storing it will move this File under the new parent.

TYPE: Optional[str]

version_label

The version label for this entity. Updates to the entity will increment the version number.

TYPE: Optional[str]

version_comment

The version comment for this entity

TYPE: Optional[str]

data_file_handle_id

ID of the file associated with this entity. You may define an existing data_file_handle_id to use the existing data_file_handle_id. The creator of the file must also be the owner of the data_file_handle_id to have permission to store the file.

TYPE: Optional[str]

external_url

The external URL of this file. If this is set AND synapse_store is False, only a reference to this URL and the file metadata will be stored in Synapse. The file itself will not be uploaded. If this attribute is set it will override the path.

TYPE: Optional[str]

activity

The Activity model represents the main record of Provenance in Synapse. It is analygous to the Activity defined in the W3C Specification on Provenance. Activity cannot be removed during a store operation by setting it to None. You must use: synapseclient.models.Activity.delete_async or [synapseclient.models.Activity.disassociate_from_entity_async][].

TYPE: Optional[Activity]

annotations

Additional metadata associated with the folder. The key is the name of your desired annotations. The value is an object containing a list of values (use empty list to represent no values for key) and the value type associated with all values in the list. To remove all annotations set this to an empty dict {} or None and store the entity.

TYPE: Optional[Dict[str, Union[List[str], List[bool], List[float], List[int], List[date], List[datetime]]]]

ATTRIBUTE DESCRIPTION
content_type

(New Upload Only) Used to manually specify Content-type header, for example 'application/png' or 'application/json; charset=UTF-8'. If not specified, the content type will be derived from the file extension.

This can be specified only during the initial store of this file or any time there is a new file to upload. In order to change this after the File has been created use synapseclient.models.File.change_metadata.

TYPE: Optional[str]

content_size

(New Upload Only) The size of the file in bytes. This can be specified only during the initial creation of the File. This is also only applicable to files not uploaded to Synapse. ie: synapse_store is False.

TYPE: Optional[int]

ATTRIBUTE DESCRIPTION
content_md5

(Store only) The MD5 of the file is known. If not supplied this will be computed in the client is possible. If supplied for a file entity already stored in Synapse it will be calculated again to check if a new upload needs to occur. This will not be filled in during a read for data. It is only used during a store operation. To retrieve the md5 of the file after read from synapse use the .file_handle.content_md5 attribute.

TYPE: Optional[str]

create_or_update

(Store only) Indicates whether the method should automatically perform an update if the file conflicts with an existing Synapse object.

TYPE: bool

force_version

(Store only) Indicates whether the method should increment the version of the object if something within the entity has changed. For example updating the description or name. You may set this to False and an update to the entity will not increment the version.

Updating the version_label attribute will also cause a version update regardless of this flag.

An update to the MD5 of the file will force a version update regardless of this flag.

TYPE: bool

is_restricted

(Store only) If set to true, an email will be sent to the Synapse access control team to start the process of adding terms-of-use or review board approval for this entity. You will be contacted with regards to the specific data being restricted and the requirements of access.

This may be used only by an administrator of the specified file.

TYPE: bool

merge_existing_annotations

(Store only) Works in conjunction with create_or_update in that this is only evaluated if create_or_update is True. If this entity exists in Synapse that has annotations that are not present in a store operation, these annotations will be added to the entity. If this is False any annotations that are not present within a store operation will be removed from this entity. This allows one to complete a destructive update of annotations on an entity.

TYPE: bool

associate_activity_to_new_version

(Store only) Works in conjunction with create_or_update in that this is only evaluated if create_or_update is True. When true an activity already attached to the current version of this entity will be associated the new version during a store operation if the version was updated. This is useful if you are updating the entity and want to ensure that the activity is persisted onto the new version the entity.

TYPE: bool

synapse_store

(Store only) Whether the File should be uploaded or if false: only the path should be stored when synapseclient.models.File.store is called.

TYPE: bool

ATTRIBUTE DESCRIPTION
download_file

(Get only) If True the file will be downloaded.

TYPE: bool

if_collision

(Get only) Determines how to handle file collisions. Defaults to "keep.both". May be:

  • overwrite.local
  • keep.local
  • keep.both

TYPE: str

synapse_container_limit

(Get only) A Synanpse ID used to limit the search in Synapse if file is specified as a local file. That is, if the file is stored in multiple locations in Synapse only the ones in the specified folder/project will be returned.

TYPE: Optional[str]

ATTRIBUTE DESCRIPTION
etag

(Read Only) Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle concurrent updates. Since the E-Tag changes every time an entity is updated it is used to detect when a client's current representation of an entity is out-of-date.

TYPE: Optional[str]

created_on

(Read Only) The date this entity was created.

TYPE: Optional[str]

modified_on

(Read Only) The date this entity was last modified.

TYPE: Optional[str]

created_by

(Read Only) The ID of the user that created this entity.

TYPE: Optional[str]

modified_by

(Read Only) The ID of the user that last modified this entity.

TYPE: Optional[str]

version_number

(Read Only) The version number issued to this version on the object.

TYPE: Optional[int]

is_latest_version

(Read Only) If this is the latest version of the object.

TYPE: Optional[bool]

file_handle

(Read Only) The file handle associated with this entity.

TYPE: Optional[FileHandle]

Source code in synapseclient/models/file.py
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
@dataclass()
@async_to_sync
class File(FileSynchronousProtocol, AccessControllable):
    """A file within Synapse.

    Attributes:
        id: The unique immutable ID for this file. A new ID will be generated for new
            Files. Once issued, this ID is guaranteed to never change or be re-issued.
        name: The name of this entity. Must be 256 characters or less. Names may only
            contain: letters, numbers, spaces, underscores, hyphens, periods, plus
            signs, apostrophes, and parentheses. If not specified, the name will be
            derived from the file name.
        path: The path to the file on disk. Using shorthand `~` will be expanded to the
            user's home directory.

            This is used during a `get` operation to specify where to download the file
            to. It should be pointing to a directory.

            This is also used during a `store` operation to specify the file to upload.
            It should be pointing to a file.

        description: The description of this file. Must be 1000 characters or less.
        parent_id: The ID of the Entity that is the parent of this Entity. Setting this
            to a new value and storing it will move this File under the new parent.
        version_label: The version label for this entity. Updates to the entity will
            increment the version number.
        version_comment: The version comment for this entity
        data_file_handle_id: ID of the file associated with this entity. You may define
            an existing data_file_handle_id to use the existing data_file_handle_id. The
            creator of the file must also be the owner of the data_file_handle_id to
            have permission to store the file.
        external_url: The external URL of this file. If this is set AND `synapse_store`
            is False, only a reference to this URL and the file metadata will be stored
            in Synapse. The file itself will not be uploaded. If this attribute is set
            it will override the `path`.
        activity: The Activity model represents the main record of Provenance in
            Synapse. It is analygous to the Activity defined in the
            [W3C Specification](https://www.w3.org/TR/prov-n/) on Provenance. Activity
            cannot be removed during a store operation by setting it to None. You must
            use: [synapseclient.models.Activity.delete_async][] or
            [synapseclient.models.Activity.disassociate_from_entity_async][].
        annotations: Additional metadata associated with the folder. The key is the name
            of your desired annotations. The value is an object containing a list of
            values (use empty list to represent no values for key) and the value type
            associated with all values in the list. To remove all annotations set this
            to an empty dict `{}` or None and store the entity.

    Attributes:
        content_type: (New Upload Only)
            Used to manually specify Content-type header, for example
            'application/png' or 'application/json; charset=UTF-8'. If not specified,
            the content type will be derived from the file extension.


            This can be specified only during the initial store of this file or any time
            there is a new file to upload.
            In order to change this after the File has been created use
            [synapseclient.models.File.change_metadata][].
        content_size: (New Upload Only)
            The size of the file in bytes. This can be specified only during the initial
            creation of the File. This is also only applicable to files not uploaded to
            Synapse. ie: `synapse_store` is False.

    Attributes:
        content_md5: (Store only) The MD5 of the file is known. If not supplied this
            will be computed in the client is possible. If supplied for a file entity
            already stored in Synapse it will be calculated again to check if a new
            upload needs to occur. This will not be filled in during a read for data. It
            is only used during a store operation. To retrieve the md5 of the file after
            read from synapse use the `.file_handle.content_md5` attribute.
        create_or_update: (Store only)
            Indicates whether the method should automatically perform an
            update if the `file` conflicts with an existing Synapse object.
        force_version: (Store only)
            Indicates whether the method should increment the version of the object if
            something within the entity has changed. For example updating the
            description or name. You may set this to False and an update to the
            entity will not increment the version.

            Updating the `version_label` attribute will also cause a version update
            regardless  of this flag.

            An update to the MD5 of the file will force a version update regardless of
            this  flag.
        is_restricted: (Store only)
            If set to true, an email will be sent to the Synapse access control
            team to start the process of adding terms-of-use or review board approval
            for this entity. You will be contacted with regards to the specific data
            being restricted and the requirements of access.

            This may be used only by an administrator of the specified file.
        merge_existing_annotations: (Store only)
            Works in conjunction with `create_or_update` in that this is only evaluated
            if `create_or_update` is True. If this entity exists in Synapse that has
            annotations that are not present in a store operation, these annotations
            will be added to the entity. If this is False any annotations that are not
            present within a store operation will be removed from this entity. This
            allows one to complete a destructive update of annotations on an entity.
        associate_activity_to_new_version: (Store only)
            Works in conjunction with `create_or_update` in that this is only evaluated
            if `create_or_update` is True. When true an activity already attached to the
            current version of this entity will be associated the new version during a
            store operation if the version was updated. This is useful if you are
            updating the entity and want to ensure that the activity is persisted onto
            the new version the entity.
        synapse_store: (Store only)
            Whether the File should be uploaded or if false: only the path should
            be stored when [synapseclient.models.File.store][] is called.

    Attributes:
        download_file: (Get only) If True the file will be downloaded.
        if_collision: (Get only)
            Determines how to handle file collisions. Defaults to "keep.both". May be:

            - `overwrite.local`
            - `keep.local`
            - `keep.both`
        synapse_container_limit: (Get only)
            A Synanpse ID used to limit the search in Synapse if
            file is specified as a local file. That is, if the file is stored in
            multiple locations in Synapse only the ones in the specified folder/project
            will be returned.

    Attributes:
        etag: (Read Only) Synapse employs an Optimistic Concurrency Control (OCC) scheme
            to handle concurrent updates. Since the E-Tag changes every time an entity
            is updated it is used to detect when a client's current representation of an
            entity is out-of-date.
        created_on: (Read Only) The date this entity was created.
        modified_on: (Read Only) The date this entity was last modified.
        created_by: (Read Only) The ID of the user that created this entity.
        modified_by: (Read Only) The ID of the user that last modified this entity.
        version_number: (Read Only) The version number issued to this version on the
            object.
        is_latest_version: (Read Only) If this is the latest version of the object.
        file_handle: (Read Only) The file handle associated with this entity.
    """

    id: Optional[str] = None
    """The unique immutable ID for this file. A new ID will be generated for new Files.
    Once issued, this ID is guaranteed to never change or be re-issued."""

    name: Optional[str] = None
    """
    The name of this entity. Must be 256 characters or less.
    Names may only contain: letters, numbers, spaces, underscores, hyphens, periods,
    plus signs, apostrophes, and parentheses. If not specified, the name will be
    derived from the file name.
    """

    path: Optional[str] = field(default=None, compare=False)
    """The path to the file on disk. Using shorthand `~` will be expanded to the user's
    home directory.

    This is used during a `get` operation to specify where to download the file to. It
    should be pointing to a directory.

    This is also used during a `store` operation to specify the file to upload. It
    should be pointing to a file."""

    description: Optional[str] = None
    """The description of this file. Must be 1000 characters or less."""

    parent_id: Optional[str] = None
    """The ID of the Entity that is the parent of this Entity. Setting this to a new
    value and storing it will move this File under the new parent."""

    version_label: Optional[str] = None
    """The version label for this entity. Updates to the entity will increment the
    version number."""

    version_comment: Optional[str] = None
    """The version comment for this entity."""

    data_file_handle_id: Optional[str] = None
    """
    ID of the file handle associated with this entity. You may define an existing
    data_file_handle_id to use the existing data_file_handle_id. The creator of the
    file must also be the owner of the data_file_handle_id to have permission to
    store the file.
    """

    external_url: Optional[str] = field(default=None, compare=False)
    """
    The external URL of this file. If this is set AND `synapse_store` is False, only
    a reference to this URL and the file metadata will be stored in Synapse. The file
    itself will not be uploaded. If this attribute is set it will override the `path`.
    """

    activity: Optional[Activity] = field(default=None, compare=False)
    """The Activity model represents the main record of Provenance in Synapse.  It is
    analygous to the Activity defined in the
    [W3C Specification](https://www.w3.org/TR/prov-n/) on Provenance. Activity cannot
    be removed during a store operation by setting it to None. You must use:
    [synapseclient.models.Activity.delete_async][] or
    [synapseclient.models.Activity.disassociate_from_entity_async][].
    """

    annotations: Optional[
        Dict[
            str,
            Union[
                List[str],
                List[bool],
                List[float],
                List[int],
                List[date],
                List[datetime],
            ],
        ]
    ] = field(default_factory=dict, compare=False)
    """Additional metadata associated with the folder. The key is the name of your
    desired annotations. The value is an object containing a list of values
    (use empty list to represent no values for key) and the value type associated with
    all values in the list. To remove all annotations set this to an empty dict `{}`."""

    content_type: Optional[str] = None
    """
    (New Upload Only)
    Used to manually specify Content-type header, for example 'application/png'
    or 'application/json; charset=UTF-8'. If not specified, the content type will be
    derived from the file extension.

    This can be specified only during the initial store of this file. In order to change
    this after the File has been created use
    [synapseclient.models.File.change_metadata][].
    """

    content_size: Optional[int] = None
    """
    (New Upload Only)
    The size of the file in bytes. This can be specified only during the initial
    creation of the File. This is also only applicable to files not uploaded to Synapse.
    ie: `synapse_store` is False.
    """

    content_md5: Optional[str] = field(default=None, compare=False)
    """
    (Store only)
    The MD5 of the file is known. If not supplied this will be computed in the client
    is possible. If supplied for a file entity already stored in Synapse it will be
    calculated again to check if a new upload needs to occur. This will not be filled
    in during a read for data. It is only used during a store operation. To retrieve
    the md5 of the file after read from synapse use the `.file_handle.content_md5`
    attribute.
    """

    create_or_update: bool = field(default=True, repr=False, compare=False)
    """
    (Store only)

    Indicates whether the method should automatically perform an update if the file
    conflicts with an existing Synapse object.
    """

    force_version: bool = field(default=True, repr=False, compare=False)
    """
    (Store only)

    Indicates whether the method should increment the version of the object if something
    within the entity has changed. For example updating the description or name.
    You may set this to False and an update to the entity will not increment the
    version.

    Updating the `version_label` attribute will also cause a version update regardless
    of this flag.

    An update to the MD5 of the file will force a version update regardless of this
    flag.
    """

    is_restricted: bool = field(default=False, repr=False)
    """
    (Store only)

    If set to true, an email will be sent to the Synapse access control team to start
    the process of adding terms-of-use or review board approval for this entity.
    You will be contacted with regards to the specific data being restricted and the
    requirements of access.

    This may be used only by an administrator of the specified file.
    """

    merge_existing_annotations: bool = field(default=True, repr=False, compare=False)
    """
    (Store only)

    Works in conjunction with `create_or_update` in that this is only evaluated if
    `create_or_update` is True. If this entity exists in Synapse that has annotations
    that are not present in a store operation, these annotations will be added to the
    entity. If this is False any annotations that are not present within a store
    operation will be removed from this entity. This allows one to complete a
    destructive update of annotations on an entity.
    """

    associate_activity_to_new_version: bool = field(
        default=False, repr=False, compare=False
    )
    """
    (Store only)

    Works in conjunction with `create_or_update` in that this is only evaluated if
    `create_or_update` is True. When true an activity already attached to the current
    version of this entity will be associated the new version during a store operation
    if the version was updated. This is useful if you are updating the entity and want
    to ensure that the activity is persisted onto the new version the entity.

    When this is False the activity will not be associated to the new version of the
    entity during a store operation.

    Regardless of this setting, if you have an Activity object on the entity it will be
    persisted onto the new version. This is only used when you don't have an Activity
    object on the entity.
    """

    _present_manifest_fields: List[str] = field(default=None, repr=False, compare=False)
    """Hidden attribute to pass along what columns were present in a manifest upload."""

    synapse_store: bool = field(default=True, repr=False)
    """
    (Store only)

    Whether the File should be uploaded or if false: only the path should be stored when
    [synapseclient.models.File.store][] is called.
    """

    download_file: bool = field(default=True, repr=False, compare=False)
    """
    (Get only)

    If True the file will be downloaded."""

    if_collision: str = field(default="keep.both", repr=False, compare=False)
    """
    (Get only)

    Determines how to handle file collisions. Defaults to "keep.both".
            May be

            - `overwrite.local`
            - `keep.local`
            - `keep.both`
    """

    synapse_container_limit: Optional[str] = field(
        default=None, repr=False, compare=False
    )
    """A Synanpse ID used to limit the search in Synapse if file is specified as a local
    file. That is, if the file is stored in multiple locations in Synapse only the
    ones in the specified folder/project will be returned."""

    etag: Optional[str] = field(default=None, compare=False)
    """
    (Read Only)
    Synapse employs an Optimistic Concurrency Control (OCC) scheme to handle
    concurrent updates. Since the E-Tag changes every time an entity is updated it is
    used to detect when a client's current representation of an entity is out-of-date.
    """

    created_on: Optional[str] = field(default=None, compare=False)
    """(Read Only) The date this entity was created."""

    modified_on: Optional[str] = field(default=None, compare=False)
    """(Read Only) The date this entity was last modified."""

    created_by: Optional[str] = field(default=None, compare=False)
    """(Read Only) The ID of the user that created this entity."""

    modified_by: Optional[str] = field(default=None, compare=False)
    """(Read Only) The ID of the user that last modified this entity."""

    version_number: Optional[int] = field(default=None, compare=False)
    """(Read Only) The version number issued to this version on the object."""

    is_latest_version: Optional[bool] = field(default=None, compare=False)
    """(Read Only) If this is the latest version of the object."""

    file_handle: Optional[FileHandle] = field(default=None, compare=False)
    """(Read Only) The file handle associated with this entity."""

    _last_persistent_instance: Optional["File"] = field(
        default=None, repr=False, compare=False
    )
    """The last persistent instance of this object. This is used to determine if the
    object has been changed and needs to be updated in Synapse."""

    @property
    def has_changed(self) -> bool:
        """Determines if the object has been changed and needs to be updated in Synapse."""
        return (
            not self._last_persistent_instance or self._last_persistent_instance != self
        )

    def _set_last_persistent_instance(self) -> None:
        """Stash the last time this object interacted with Synapse. This is used to
        determine if the object has been changed and needs to be updated in Synapse."""
        del self._last_persistent_instance
        self._last_persistent_instance = dataclasses.replace(self)
        self._last_persistent_instance.activity = (
            dataclasses.replace(self.activity) if self.activity else None
        )
        self._last_persistent_instance.annotations = (
            deepcopy(self.annotations) if self.annotations else {}
        )

    def _fill_from_file_handle(self) -> None:
        """Fill the file object from the file handle."""
        if self.file_handle:
            self.data_file_handle_id = self.file_handle.id
            self.content_type = self.file_handle.content_type
            self.content_size = self.file_handle.content_size
            self.external_url = self.file_handle.external_url

    def fill_from_dict(
        self,
        synapse_file: Union[Synapse_File, Dict[str, Union[bool, str, int]]],
        set_annotations: bool = True,
    ) -> "File":
        """
        Converts a response from the REST API into this dataclass.

        Arguments:
            synapse_file: The response from the REST API.
            set_annotations: Whether to set the annotations from the response.

        Returns:
            The File object.
        """
        self.id = synapse_file.get("id", None)
        self.name = synapse_file.get("name", None)
        self.description = synapse_file.get("description", None)
        self.etag = synapse_file.get("etag", None)
        self.created_on = synapse_file.get("createdOn", None)
        self.modified_on = synapse_file.get("modifiedOn", None)
        self.created_by = synapse_file.get("createdBy", None)
        self.modified_by = synapse_file.get("modifiedBy", None)
        self.parent_id = synapse_file.get("parentId", None)
        self.version_number = synapse_file.get("versionNumber", None)
        self.version_label = synapse_file.get("versionLabel", None)
        self.version_comment = synapse_file.get("versionComment", None)
        self.is_latest_version = synapse_file.get("isLatestVersion", False)
        self.data_file_handle_id = synapse_file.get("dataFileHandleId", None)
        self.path = synapse_file.get("path", self.path)
        synapse_file_handle = synapse_file.get("_file_handle", None)
        if synapse_file_handle:
            file_handle = self.file_handle or FileHandle()
            self.file_handle = file_handle.fill_from_dict(
                synapse_instance=synapse_file_handle
            )
            self._fill_from_file_handle()

        if set_annotations:
            self.annotations = Annotations.from_dict(
                synapse_file.get("annotations", {})
            )
        return self

    def _cannot_store(self) -> bool:
        """Determines based on some guard conditions if we are unable to continue with
        a store operation."""
        return (
            not (
                self.id is not None
                and (self.path is not None or self.data_file_handle_id is not None)
            )
            and not (self.path is not None and self.parent_id is not None)
            and not (
                self.parent_id is not None and self.data_file_handle_id is not None
            )
        )

    async def _load_local_md5(self) -> None:
        """Load the MD5 of the file if it's a local file and we have not already loaded
        it."""
        if not self.content_md5 and self.path and os.path.isfile(self.path):
            self.content_md5 = utils.md5_for_file_hex(filename=self.path)

    async def _find_existing_file(
        self, *, synapse_client: Optional[Synapse] = None
    ) -> Union["File", None]:
        """Determines if the file already exists in Synapse. If it does it will return
        the file object, otherwise it will return None. This is used to determine if the
        file should be updated or created."""

        async def get_file(existing_id: str) -> "File":
            """Small wrapper to retrieve a file instance without raising an error if it
            does not exist.

            Arguments:
                existing_id: The ID of the file to retrieve.

            Returns:
                The file object if it exists, otherwise None.
            """
            try:
                file_copy = File(
                    id=existing_id,
                    download_file=False,
                    version_number=self.version_number,
                    synapse_container_limit=self.synapse_container_limit,
                    parent_id=self.parent_id,
                )
                return await file_copy.get_async(
                    synapse_client=synapse_client,
                    include_activity=self.activity is not None
                    or self.associate_activity_to_new_version,
                )
            except SynapseFileNotFoundError:
                return None

        if (
            self.create_or_update
            and not self._last_persistent_instance
            and (
                existing_file_id := await get_id(
                    entity=self,
                    failure_strategy=None,
                    synapse_client=synapse_client,
                )
            )
            and (existing_file := await get_file(existing_file_id))
        ):
            return existing_file
        return None

    def _determine_fields_to_ignore_in_merge(self) -> List[str]:
        """This is used to determine what fields should not be merged when merging two
        entities. This allows for a fine tuned destructive update of an entity.

        This also has special handling during a manifest upload of files. If a manifest
        is specifying fields we'll use those values rather than copying them from the
        existing entity. This is to allow for a destructive update of an entity.

        """
        fields_to_not_merge = []
        if not self.merge_existing_annotations:
            fields_to_not_merge.append("annotations")

        if not self.associate_activity_to_new_version:
            fields_to_not_merge.append("activity")

        if self._present_manifest_fields:
            if "name" in self._present_manifest_fields:
                fields_to_not_merge.append("name")

            if "contentType" in self._present_manifest_fields:
                fields_to_not_merge.append("content_type")

        return fields_to_not_merge

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Store: {self.path if self.path else self.id}"
    )
    async def store_async(
        self,
        parent: Optional[Union["Folder", "Project"]] = None,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """
        Store the file in Synapse. With this method you may:

        - Upload a file into Synapse
        - Update the metadata of a file in Synapse
        - Store a File object in Synapse without updating a file by setting
            `synapse_store` to False.
        - Change the name of a file in Synapse by setting the `name` attribute of the
            File object. Also see the [synapseclient.models.File.change_metadata][]
            method for changing the name of the downloaded file.
        - Moving a file to a new parent by setting the `parent_id` attribute of the
            File object.

        If no Name is specified this will be derived from the file name. This is the
        reccommended way to store a file in Synapse.

        Please note:
        The file, as it appears on disk, will be the file that is downloaded from
        Synapse. The name of the actual File is different from the name of the File
        Entity in Synapse. It is generally not reccommended to specify a different
        name for the Entity and the file as it will cause confusion and potential
        conflicts later on.

        Arguments:
            parent: The parent folder or project to store the file in. May also be
                specified in the File object. If both are provided the parent passed
                into `store` will take precedence.
            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 file object.

        Raises:
            ValueError: If the file does not have an ID and a path, or a path and a
                parent ID, or a data file handle ID and a parent ID.

        Example: Using this function
            File with the ID `syn123` at path `path/to/file.txt`:

                file_instance = await File(id="syn123", path="path/to/file.txt").store_async()

            File at the path `path/to/file.txt` and a parent folder with the ID `syn456`:

                file_instance = await File(path="path/to/file.txt", parent_id="syn456").store_async()

            File at the path `path/to/file.txt` and a parent folder with the ID `syn456`:

                file_instance = await File(path="path/to/file.txt").store_async(parent=Folder(id="syn456"))

            File with a parent and existing file handle (This allows multiple entities to reference the underlying file):

                file_instance = await File(data_file_handle_id="123", parent_id="syn456").store_async()

            Rename a file (Does not update the file on disk or the name of the downloaded file):

                file_instance = await File(id="syn123", download_file=False).get_async()
                print(file_instance.name)  ## prints, e.g., "my_file.txt"
                await file_instance.change_metadata_async(name="my_new_name_file.txt")

            Rename a file, and the name of the file as downloaded
                (Does not update the file on disk). Is is reccommended that `name` and
                `download_as` match to prevent confusion later on:

                file_instance = await File(id="syn123", download_file=False).get_async()
                print(file_instance.name)  ## prints, e.g., "my_file.txt"
                await file_instance.change_metadata_async(name="my_new_name_file.txt", download_as="my_new_name_file.txt")

        """
        self.parent_id = parent.id if parent else self.parent_id
        if self._cannot_store():
            raise ValueError(
                "The file must have an (ID with a (path or `data_file_handle_id`)), or a "
                "(path with a (`parent_id` or parent with an id)), or a "
                "(data_file_handle_id with a (`parent_id` or parent with an id)) to store."
            )
        self.name = self.name or (guess_file_name(self.path) if self.path else None)
        client = Synapse.get_client(synapse_client=synapse_client)

        if existing_file := await self._find_existing_file(synapse_client=client):
            merge_dataclass_entities(
                source=existing_file,
                destination=self,
                fields_to_ignore=self._determine_fields_to_ignore_in_merge(),
            )

        if self.path:
            self.path = os.path.expanduser(self.path)
            async with client._get_parallel_file_transfer_semaphore(
                asyncio_event_loop=asyncio.get_running_loop()
            ):
                await self._upload_file(synapse_client=client)
        elif self.data_file_handle_id:
            self.path = client.cache.get(file_handle_id=self.data_file_handle_id)

        if self.has_changed:
            synapse_file = Synapse_File(
                id=self.id,
                path=self.path,
                description=self.description,
                etag=self.etag,
                name=self.name,
                parent=parent.id if parent else self.parent_id,
                contentType=self.content_type,
                contentSize=self.content_size,
                dataFileHandleId=self.data_file_handle_id,
                synapseStore=self.synapse_store,
                modifiedOn=self.modified_on,
                versionLabel=self.version_label,
                versionNumber=self.version_number,
                versionComment=self.version_comment,
            )
            delete_none_keys(synapse_file)

            entity = await store_entity(
                resource=self, entity=synapse_file, synapse_client=client
            )

            self.fill_from_dict(synapse_file=entity, set_annotations=False)

        re_read_required = await store_entity_components(
            root_resource=self, synapse_client=client
        )
        if re_read_required:
            before_download_file = self.download_file
            self.download_file = False
            await self.get_async(
                synapse_client=client,
            )
            self.download_file = before_download_file

        self._set_last_persistent_instance()

        client.logger.debug(f"Stored File {self.name}, id: {self.id}: {self.path}")
        # Clear the content_md5 so that it is recalculated if the file is updated
        self.content_md5 = None
        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Change_Metadata: {self.id}"
    )
    async def change_metadata_async(
        self,
        name: Optional[str] = None,
        download_as: Optional[str] = None,
        content_type: Optional[str] = None,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """
        Change File Entity metadata for properties that are immutable after creation
        through the store method.

        Arguments:
            name: Specify to change the filename of a file as seen on Synapse.
            download_as: Specify filename to change the filename of a filehandle.
            content_type: Specify content type to change the content type of a
                filehandle.
            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 file object.

        Example: Using this function
            Can be used to change the filename, the filename when the file is
            downloaded, or the file content-type without downloading:

                file_entity = await File(id="syn123", download_file=False).get_async()
                print(os.path.basename(file_entity.path))  ## prints, e.g., "my_file.txt"
                file_entity = await file_entity.change_metadata_async(name="my_new_name_file.txt", download_as="my_new_downloadAs_name_file.txt", content_type="text/plain")
                print(os.path.basename(file_entity.path))  ## prints, "my_new_downloadAs_name_file.txt"
                print(file_entity.name) ## prints, "my_new_name_file.txt"

        Raises:
            ValueError: If the file does not have an ID to change metadata.
        """
        if not self.id:
            raise ValueError("The file must have an ID to change metadata.")
        from synapseutils.copy_functions import changeFileMetaData

        loop = asyncio.get_event_loop()

        syn = Synapse.get_client(synapse_client=synapse_client)
        entity = await loop.run_in_executor(
            None,
            lambda: changeFileMetaData(
                syn=syn,
                entity=self.id,
                name=name,
                downloadAs=download_as,
                contentType=content_type,
                forceVersion=self.force_version,
            ),
        )

        self.fill_from_dict(synapse_file=entity, set_annotations=True)
        self._set_last_persistent_instance()
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Change metadata for file {self.name}, id: {self.id}: {self.path}"
        )
        return self

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Get: {self.id}, {self.path}"
    )
    async def get_async(
        self,
        include_activity: bool = False,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """
        Get the file from Synapse. You may retrieve a File entity by either:

        - id
        - path


        If you specify both, the `id` will take precedence.


        If you specify the `path` and the file is stored in multiple locations in
        Synapse only the first one found will be returned. The other matching files
        will be printed to the console.


        You may also specify a `version_number` to get a specific version of the file.

        Arguments:
            include_activity: If True the activity will be included in the file
                if it exists.
            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 file object.

        Raises:
            ValueError: If the file does not have an ID or path to get.


        Example: Using this function
            Assuming you have a file with the ID "syn123":

                file_instance = await File(id="syn123").get_async()

            Assuming you want to download a file to this directory: "path/to/directory":

                file_instance = await File(path="path/to/directory").get_async()
        """
        if not self.id and not self.path:
            raise ValueError("The file must have an ID or path to get.")
        syn = Synapse.get_client(synapse_client=synapse_client)

        await self._load_local_md5()

        await get_from_entity_factory(
            entity_to_update=self,
            synapse_id_or_path=self.id or self.path,
            version=self.version_number,
            if_collision=self.if_collision,
            limit_search=self.synapse_container_limit or self.parent_id,
            download_file=self.download_file,
            download_location=os.path.dirname(self.path)
            if self.path and os.path.isfile(self.path)
            else self.path,
            md5=self.content_md5,
            synapse_client=syn,
        )

        if (
            self.data_file_handle_id
            and (not self.path or (self.path and not os.path.isfile(self.path)))
            and (cached_path := syn.cache.get(file_handle_id=self.data_file_handle_id))
        ):
            self.path = cached_path

        if include_activity:
            self.activity = await Activity.from_parent_async(
                parent=self, synapse_client=synapse_client
            )

        self._set_last_persistent_instance()
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Got file {self.name}, id: {self.id}, path: {self.path}"
        )
        return self

    @classmethod
    async def from_id_async(
        cls,
        synapse_id: str,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """Wrapper for [synapseclient.models.File.get][].

        Arguments:
            synapse_id: The ID of the file in Synapse.
            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 file object.

        Example: Using this function
            Assuming you have a file with the ID "syn123":

                file_instance = await File.from_id_async(synapse_id="syn123")
        """
        return await cls(id=synapse_id).get_async(
            synapse_client=synapse_client,
        )

    @classmethod
    async def from_path_async(
        cls,
        path: str,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """Get the file from Synapse. If the path of the file matches multiple files
        within Synapse the first one found will be returned. The other matching
        files will be printed to the console.


        Wrapper for [synapseclient.models.File.get][].

        Arguments:
            path: The path to the file on disk.
            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 file object.

        Example: Using this function
            Assuming you have a file at the path "path/to/file.txt":

                file_instance = await File.from_path_async(path="path/to/file.txt")
        """
        return await cls(path=path).get_async(
            synapse_client=synapse_client,
        )

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Delete: {self.id}"
    )
    async def delete_async(
        self,
        version_only: Optional[bool] = False,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> None:
        """
        Delete the file from Synapse using the ID of the file.

        Arguments:
            version_only: If True only the version specified in the `version_number`
                attribute of the file will be deleted. If False the entire file will
                be deleted.
            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:
            None

        Raises:
            ValueError: If the file does not have an ID to delete.
            ValueError: If the file does not have a version number to delete a version,
                and `version_only` is True.

        Example: Using this function
            Assuming you have a file with the ID "syn123":

                await File(id="syn123").delete_async()
        """
        if not self.id:
            raise ValueError("The file must have an ID to delete.")
        if version_only and not self.version_number:
            raise ValueError("The file must have a version number to delete a version.")

        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None,
            lambda: Synapse.get_client(synapse_client=synapse_client).delete(
                obj=self.id,
                version=self.version_number if version_only else None,
            ),
        )
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Deleted file {self.id}"
        )

    @otel_trace_method(
        method_to_trace_name=lambda self, **kwargs: f"File_Copy: {self.id}"
    )
    async def copy_async(
        self,
        parent_id: str,
        update_existing: bool = False,
        copy_annotations: bool = True,
        copy_activity: Union[str, None] = "traceback",
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """
        Copy the file to another Synapse location. Defaults to the latest version of the
        file, or the version_number specified in the instance.

        Arguments:
            parent_id: Synapse ID of a folder/project that the copied entity is being
                copied to
            update_existing: When the destination has a file that has the same name,
                users can choose to update that file.
            copy_annotations: True to copy the annotations.
            copy_activity: Has three options to set the activity of the copied file:

                    - traceback: Creates a copy of the source files Activity.
                    - existing: Link to the source file's original Activity (if it exists)
                    - None: No activity is set
            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 copied file object.

        Example: Using this function
            Assuming you have a file with the ID "syn123" and you want to copy it to a folder with the ID "syn456":

                new_file_instance = await File(id="syn123").copy_async(parent_id="syn456")

            Copy the file but do not persist annotations or activity:

                new_file_instance = await File(id="syn123").copy_async(parent_id="syn456", copy_annotations=False, copy_activity=None)

        Raises:
            ValueError: If the file does not have an ID and parent_id to copy.
        """
        if not self.id or not parent_id:
            raise ValueError("The file must have an ID and parent_id to copy.")
        from synapseutils.copy_functions import copy

        loop = asyncio.get_event_loop()

        syn = Synapse.get_client(synapse_client=synapse_client)
        source_and_destination = await loop.run_in_executor(
            None,
            lambda: copy(
                syn=syn,
                version=self.version_number,
                entity=self.id,
                destinationId=parent_id,
                skipCopyAnnotations=not copy_annotations,
                updateExisting=update_existing,
                setProvenance=copy_activity,
            ),
        )

        parent_id = source_and_destination.get(self.id, None)
        if not parent_id:
            raise SynapseError("Failed to copy file.")
        file_copy = await File(id=parent_id, download_file=False).get_async(
            synapse_client=synapse_client
        )
        file_copy.download_file = True
        Synapse.get_client(synapse_client=synapse_client).logger.debug(
            f"Copied from file {self.id} to {parent_id} with new id of {file_copy.id}"
        )
        return file_copy

    async def _needs_upload(self, syn: Synapse) -> bool:
        """
        Determines if a file needs to be uploaded to Synapse. The following conditions
        apply:

        - The file exists and is an ExternalFileHandle and the url has changed
        - The file exists and is a local file and the MD5 has changed
        - The file is not present in Synapse

        If the file is already specifying a data_file_handle_id then it is assumed that
        the file is already uploaded to Synapse. It does not need to be uploaded and
        the only thing that will occur is the File metadata will be added to Synapse
        outside of this upload process.

        Arguments:
            syn: 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:
            True if the file needs to be uploaded, otherwise False.
        """
        needs_upload = False
        # Check if the file should be uploaded
        if self._last_persistent_instance is not None:
            if (
                self.file_handle
                and self.file_handle.concrete_type
                == "org.sagebionetworks.repo.model.file.ExternalFileHandle"
            ):
                # switching away from ExternalFileHandle or the url was updated
                needs_upload = self.synapse_store or (
                    self.file_handle.external_url != self.external_url
                )
            else:
                # Check if we need to upload a new version of an existing
                # file. If the file referred to by entity['path'] has been
                # modified, we want to upload the new version.
                # If synapeStore is false then we must upload a ExternalFileHandle
                needs_upload = (
                    not self.synapse_store
                    or not self.file_handle
                    or not (
                        exists_in_cache := syn.cache.contains(
                            self.file_handle.id, self.path
                        )
                    )
                )

                md5_stored_in_synapse = (
                    self.file_handle.content_md5 if self.file_handle else None
                )

                # Check if we got an MD5 checksum from Synapse and compare it to the local file
                if (
                    self.synapse_store
                    and needs_upload
                    and os.path.isfile(self.path)
                    and md5_stored_in_synapse
                ):
                    await self._load_local_md5()
                    if md5_stored_in_synapse == (
                        local_file_md5_hex := self.content_md5
                    ):
                        needs_upload = False

                    # If we had a cache miss, but already uploaded to Synapse we
                    # can add the file to the cache.
                    if (
                        not exists_in_cache
                        and self.file_handle
                        and self.file_handle.id
                        and local_file_md5_hex
                    ):
                        syn.cache.add(
                            file_handle_id=self.file_handle.id,
                            path=self.path,
                            md5=local_file_md5_hex,
                        )
        elif self.data_file_handle_id is not None:
            needs_upload = False
        else:
            needs_upload = True
        return needs_upload

    async def _upload_file(
        self,
        *,
        synapse_client: Optional[Synapse] = None,
    ) -> "File":
        """The upload process for a file. This will upload the file to Synapse if it
        needs to be uploaded. If the file does not need to be uploaded the file
        metadata will be added to Synapse outside of this upload process.

        Arguments:
            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 file object.
        """
        syn = Synapse.get_client(synapse_client=synapse_client)

        needs_upload = await self._needs_upload(syn=syn)

        if needs_upload:
            parent_id_for_upload = self.parent_id

            if not parent_id_for_upload:
                raise SynapseMalformedEntityError(
                    "Entities of type File must have a parentId."
                )

            updated_file_handle = await upload_file_handle(
                syn=syn,
                parent_entity_id=parent_id_for_upload,
                path=(
                    self.path
                    if (self.synapse_store or self.external_url is None)
                    else self.external_url
                ),
                synapse_store=self.synapse_store,
                md5=self.content_md5,
                file_size=self.content_size,
                mimetype=self.content_type,
            )

            self.file_handle = FileHandle().fill_from_dict(updated_file_handle)
            self._fill_from_file_handle()

        return self

    def _convert_into_legacy_file(self) -> SynapseFile:
        """Convert the file object into a SynapseFile object."""
        return_data = SynapseFile(
            id=self.id,
            name=self.name,
            description=self.description,
            etag=self.etag,
            createdOn=self.created_on,
            modifiedOn=self.modified_on,
            createdBy=self.created_by,
            modifiedBy=self.modified_by,
            parentId=self.parent_id,
            versionNumber=self.version_number,
            versionLabel=self.version_label,
            versionComment=self.version_comment,
            dataFileHandleId=self.data_file_handle_id,
            path=self.path,
            properties={
                "isLatestVersion": self.is_latest_version,
            },
            _file_handle=(
                self.file_handle._convert_into_legacy_file_handle()
                if self.file_handle
                else None
            ),
            annotations=self.annotations,
        )
        delete_none_keys(return_data)
        return return_data

Functions

get

get(include_activity: bool = False, *, synapse_client: Optional[Synapse] = None) -> File

Get the file from Synapse. You may retrieve a File entity by either:

  • id
  • path

If you specify both, the id will take precedence.

If you specify the path and the file is stored in multiple locations in Synapse only the first one found will be returned. The other matching files will be printed to the console.

You may also specify a version_number to get a specific version of the file.

PARAMETER DESCRIPTION
include_activity

If True the activity will be included in the file if it exists.

TYPE: bool DEFAULT: False

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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
File

The file object.

RAISES DESCRIPTION
ValueError

If the file does not have an ID or path to get.

Using this function

Assuming you have a file with the ID "syn123":

file_instance = File(id="syn123").get()

Assuming you want to download a file to this directory: "path/to/directory":

file_instance = File(path="path/to/directory").get()
Source code in synapseclient/models/protocols/file_protocol.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
def get(
    self,
    include_activity: bool = False,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """
    Get the file from Synapse. You may retrieve a File entity by either:

    - id
    - path


    If you specify both, the `id` will take precedence.


    If you specify the `path` and the file is stored in multiple locations in Synapse
    only the first one found will be returned. The other matching files will be
    printed to the console.


    You may also specify a `version_number` to get a specific version of the file.

    Arguments:
        include_activity: If True the activity will be included in the file if it exists.
        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 file object.

    Raises:
        ValueError: If the file does not have an ID or path to get.


    Example: Using this function
        Assuming you have a file with the ID "syn123":

            file_instance = File(id="syn123").get()

        Assuming you want to download a file to this directory: "path/to/directory":

            file_instance = File(path="path/to/directory").get()
    """
    return self

store

store(parent: Optional[Union[Folder, Project]] = None, *, synapse_client: Optional[Synapse] = None) -> File

Store the file in Synapse. With this method you may:

  • Upload a file into Synapse
  • Update the metadata of a file in Synapse
  • Store a File object in Synapse without updating a file by setting synapse_store to False.
  • Change the name of a file in Synapse by setting the name attribute of the File object. Also see the synapseclient.models.File.change_metadata method for changing the name of the downloaded file.
  • Moving a file to a new parent by setting the parent_id attribute of the File object.
PARAMETER DESCRIPTION
parent

The parent folder or project to store the file in. May also be specified in the File object. If both are provided the parent passed into store will take precedence.

TYPE: Optional[Union[Folder, Project]] DEFAULT: None

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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
File

The file object.

Using this function

File with the ID syn123 at path path/to/file.txt:

file_instance = File(id="syn123", path="path/to/file.txt").store()

File at the path path/to/file.txt and a parent folder with the ID syn456:

file_instance = File(path="path/to/file.txt", parent_id="syn456").store()

File at the path path/to/file.txt and a parent folder with the ID syn456:

file_instance = File(path="path/to/file.txt").store(parent=Folder(id="syn456"))

Rename a file (Does not update the file on disk or the name of the downloaded file):

file_instance = File(id="syn123", download_file=False).get()
print(file_instance.name)  ## prints, e.g., "my_file.txt"
file_instance.change_metadata(name="my_new_name_file.txt")

Rename a file, and the name of the file as downloaded (Does not update the file on disk):

file_instance = File(id="syn123", download_file=False).get()
print(file_instance.name)  ## prints, e.g., "my_file.txt"
file_instance.change_metadata(name="my_new_name_file.txt", download_as="my_new_name_file.txt")
Source code in synapseclient/models/protocols/file_protocol.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def store(
    self,
    parent: Optional[Union["Folder", "Project"]] = None,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """
    Store the file in Synapse. With this method you may:

    - Upload a file into Synapse
    - Update the metadata of a file in Synapse
    - Store a File object in Synapse without updating a file by setting
        `synapse_store` to False.
    - Change the name of a file in Synapse by setting the `name` attribute of the
        File object. Also see the [synapseclient.models.File.change_metadata][]
        method for changing the name of the downloaded file.
    - Moving a file to a new parent by setting the `parent_id` attribute of the
        File object.

    Arguments:
        parent: The parent folder or project to store the file in. May also be
            specified in the File object. If both are provided the parent passed
            into `store` will take precedence.
        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 file object.


    Example: Using this function
        File with the ID `syn123` at path `path/to/file.txt`:

            file_instance = File(id="syn123", path="path/to/file.txt").store()

        File at the path `path/to/file.txt` and a parent folder with the ID `syn456`:

            file_instance = File(path="path/to/file.txt", parent_id="syn456").store()

        File at the path `path/to/file.txt` and a parent folder with the ID `syn456`:

            file_instance = File(path="path/to/file.txt").store(parent=Folder(id="syn456"))

        Rename a file (Does not update the file on disk or the name of the downloaded file):

            file_instance = File(id="syn123", download_file=False).get()
            print(file_instance.name)  ## prints, e.g., "my_file.txt"
            file_instance.change_metadata(name="my_new_name_file.txt")

        Rename a file, and the name of the file as downloaded (Does not update the file on disk):

            file_instance = File(id="syn123", download_file=False).get()
            print(file_instance.name)  ## prints, e.g., "my_file.txt"
            file_instance.change_metadata(name="my_new_name_file.txt", download_as="my_new_name_file.txt")

    """
    return self

copy

copy(parent_id: str, update_existing: bool = False, copy_annotations: bool = True, copy_activity: Union[str, None] = 'traceback', *, synapse_client: Optional[Synapse] = None) -> File

Copy the file to another Synapse location. Defaults to the latest version of the file, or the version_number specified in the instance.

PARAMETER DESCRIPTION
parent_id

Synapse ID of a folder/project that the copied entity is being copied to

TYPE: str

update_existing

When the destination has a file that has the same name, users can choose to update that file.

TYPE: bool DEFAULT: False

copy_annotations

True to copy the annotations.

TYPE: bool DEFAULT: True

copy_activity

Has three options to set the activity of the copied file:

- traceback: Creates a copy of the source files Activity.
- existing: Link to the source file's original Activity (if it exists)
- None: No activity is set

TYPE: Union[str, None] DEFAULT: 'traceback'

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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
File

The copied file object.

Using this function

Assuming you have a file with the ID "syn123" and you want to copy it to a folder with the ID "syn456":

new_file_instance = File(id="syn123").copy(parent_id="syn456")

Copy the file but do not persist annotations or activity:

new_file_instance = File(id="syn123").copy(parent_id="syn456", copy_annotations=False, copy_activity=None)
RAISES DESCRIPTION
ValueError

If the file does not have an ID and parent_id to copy.

Source code in synapseclient/models/protocols/file_protocol.py
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
def copy(
    self,
    parent_id: str,
    update_existing: bool = False,
    copy_annotations: bool = True,
    copy_activity: Union[str, None] = "traceback",
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """
    Copy the file to another Synapse location. Defaults to the latest version of the
    file, or the version_number specified in the instance.

    Arguments:
        parent_id: Synapse ID of a folder/project that the copied entity is being
            copied to
        update_existing: When the destination has a file that has the same name,
            users can choose to update that file.
        copy_annotations: True to copy the annotations.
        copy_activity: Has three options to set the activity of the copied file:

                - traceback: Creates a copy of the source files Activity.
                - existing: Link to the source file's original Activity (if it exists)
                - None: No activity is set
        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 copied file object.

    Example: Using this function
        Assuming you have a file with the ID "syn123" and you want to copy it to a folder with the ID "syn456":

            new_file_instance = File(id="syn123").copy(parent_id="syn456")

        Copy the file but do not persist annotations or activity:

            new_file_instance = File(id="syn123").copy(parent_id="syn456", copy_annotations=False, copy_activity=None)

    Raises:
        ValueError: If the file does not have an ID and parent_id to copy.
    """
    from synapseclient.models import File

    return File()

delete

delete(version_only: Optional[bool] = False, *, synapse_client: Optional[Synapse] = None) -> None

Delete the file from Synapse.

PARAMETER DESCRIPTION
version_only

If True only the version specified in the version_number attribute of the file will be deleted. If False the entire file will be deleted.

TYPE: Optional[bool] DEFAULT: False

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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
None

None

RAISES DESCRIPTION
ValueError

If the file does not have an ID to delete.

ValueError

If the file does not have a version number to delete a version, and version_only is True.

Using this function

Assuming you have a file with the ID "syn123":

File(id="syn123").delete()
Source code in synapseclient/models/protocols/file_protocol.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
def delete(
    self,
    version_only: Optional[bool] = False,
    *,
    synapse_client: Optional[Synapse] = None,
) -> None:
    """Delete the file from Synapse.

    Arguments:
        version_only: If True only the version specified in the `version_number`
            attribute of the file will be deleted. If False the entire file will
            be deleted.
        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:
        None

    Raises:
        ValueError: If the file does not have an ID to delete.
        ValueError: If the file does not have a version number to delete a version,
            and `version_only` is True.

    Example: Using this function
        Assuming you have a file with the ID "syn123":

            File(id="syn123").delete()
    """
    return None

from_id classmethod

from_id(synapse_id: str, *, synapse_client: Optional[Synapse] = None) -> File

Wrapper for synapseclient.models.File.get.

PARAMETER DESCRIPTION
synapse_id

The ID of the file in Synapse.

TYPE: str

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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
File

The file object.

Using this function

Assuming you have a file with the ID "syn123":

file_instance = File.from_id(synapse_id="syn123")
Source code in synapseclient/models/protocols/file_protocol.py
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
@classmethod
def from_id(
    cls,
    synapse_id: str,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """Wrapper for [synapseclient.models.File.get][].

    Arguments:
        synapse_id: The ID of the file in Synapse.
        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 file object.

    Example: Using this function
        Assuming you have a file with the ID "syn123":

            file_instance = File.from_id(synapse_id="syn123")
    """
    from synapseclient.models import File

    return File()

from_path classmethod

from_path(path: str, *, synapse_client: Optional[Synapse] = None) -> File

Get the file from Synapse. If the path of the file matches multiple files within Synapse the first one found will be returned. The other matching files will be printed to the console.

Wrapper for synapseclient.models.File.get.

PARAMETER DESCRIPTION
path

The path to the file on disk.

TYPE: str

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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
File

The file object.

Using this function

Assuming you have a file at the path "path/to/file.txt":

file_instance = File.from_path(path="path/to/file.txt")
Source code in synapseclient/models/protocols/file_protocol.py
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
@classmethod
def from_path(
    cls,
    path: str,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """Get the file from Synapse. If the path of the file matches multiple files
    within Synapse the first one found will be returned. The other matching
    files will be printed to the console.


    Wrapper for [synapseclient.models.File.get][].

    Arguments:
        path: The path to the file on disk.
        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 file object.

    Example: Using this function
        Assuming you have a file at the path "path/to/file.txt":

            file_instance = File.from_path(path="path/to/file.txt")
    """
    from synapseclient.models import File

    return File()

change_metadata

change_metadata(name: Optional[str] = None, download_as: Optional[str] = None, content_type: Optional[str] = None, *, synapse_client: Optional[Synapse] = None) -> File

Change File Entity metadata for properties that are immutable after creation through the store method.

PARAMETER DESCRIPTION
name

Specify to change the filename of a file as seen on Synapse.

TYPE: Optional[str] DEFAULT: None

download_as

Specify filename to change the filename of a filehandle.

TYPE: Optional[str] DEFAULT: None

content_type

Specify content type to change the content type of a filehandle.

TYPE: Optional[str] DEFAULT: None

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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
File

The file object.

Using this function

Can be used to change the filename, the filename when the file is downloaded, or the file content-type without downloading:

file_entity = File(id="syn123", download_file=False).get()
print(os.path.basename(file_entity.path))  ## prints, e.g., "my_file.txt"
file_entity = file_entity.change_metadata(name="my_new_name_file.txt", download_as="my_new_downloadAs_name_file.txt", content_type="text/plain")
print(os.path.basename(file_entity.path))  ## prints, "my_new_downloadAs_name_file.txt"
print(file_entity.name) ## prints, "my_new_name_file.txt"
RAISES DESCRIPTION
ValueError

If the file does not have an ID to change metadata.

Source code in synapseclient/models/protocols/file_protocol.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def change_metadata(
    self,
    name: Optional[str] = None,
    download_as: Optional[str] = None,
    content_type: Optional[str] = None,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "File":
    """
    Change File Entity metadata for properties that are immutable after creation
    through the store method.

    Arguments:
        name: Specify to change the filename of a file as seen on Synapse.
        download_as: Specify filename to change the filename of a filehandle.
        content_type: Specify content type to change the content type of a
            filehandle.
        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 file object.

    Example: Using this function
        Can be used to change the filename, the filename when the file is downloaded, or the file content-type without downloading:

            file_entity = File(id="syn123", download_file=False).get()
            print(os.path.basename(file_entity.path))  ## prints, e.g., "my_file.txt"
            file_entity = file_entity.change_metadata(name="my_new_name_file.txt", download_as="my_new_downloadAs_name_file.txt", content_type="text/plain")
            print(os.path.basename(file_entity.path))  ## prints, "my_new_downloadAs_name_file.txt"
            print(file_entity.name) ## prints, "my_new_name_file.txt"

    Raises:
        ValueError: If the file does not have an ID to change metadata.
    """
    return self

get_permissions

get_permissions(*, synapse_client: Optional[Synapse] = None) -> Permissions

Get the permissions that the caller has on an Entity.

PARAMETER DESCRIPTION
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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
Permissions

A Permissions object

Using this function:

Getting permissions for a Synapse Entity

permissions = File(id="syn123").get_permissions()

Getting access types list from the Permissions object

permissions.access_types
Source code in synapseclient/models/protocols/access_control_protocol.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def get_permissions(
    self,
    *,
    synapse_client: Optional[Synapse] = None,
) -> "Permissions":
    """
    Get the [permissions][synapseclient.core.models.permission.Permissions]
    that the caller has on an Entity.

    Arguments:
        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:
        A Permissions object


    Example: Using this function:
        Getting permissions for a Synapse Entity

            permissions = File(id="syn123").get_permissions()

        Getting access types list from the Permissions object

            permissions.access_types
    """
    return self

get_acl

get_acl(principal_id: int = None, *, synapse_client: Optional[Synapse] = None) -> List[str]

Get the ACL that a user or group has on an Entity.

PARAMETER DESCRIPTION
principal_id

Identifier of a user or group (defaults to PUBLIC users)

TYPE: int DEFAULT: None

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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
List[str]

An array containing some combination of ['READ', 'UPDATE', 'CREATE', 'DELETE', 'DOWNLOAD', 'MODERATE', 'CHANGE_PERMISSIONS', 'CHANGE_SETTINGS'] or an empty array

Source code in synapseclient/models/protocols/access_control_protocol.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def get_acl(
    self, principal_id: int = None, *, synapse_client: Optional[Synapse] = None
) -> List[str]:
    """
    Get the [ACL][synapseclient.core.models.permission.Permissions.access_types]
    that a user or group has on an Entity.

    Arguments:
        principal_id: Identifier of a user or group (defaults to PUBLIC users)
        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:
        An array containing some combination of
            ['READ', 'UPDATE', 'CREATE', 'DELETE', 'DOWNLOAD', 'MODERATE',
            'CHANGE_PERMISSIONS', 'CHANGE_SETTINGS']
            or an empty array
    """
    return [""]

set_permissions

set_permissions(principal_id: int = None, access_type: List[str] = None, modify_benefactor: bool = False, warn_if_inherits: bool = True, overwrite: bool = True, *, synapse_client: Optional[Synapse] = None) -> Dict[str, Union[str, list]]

Sets permission that a user or group has on an Entity. An Entity may have its own ACL or inherit its ACL from a benefactor.

PARAMETER DESCRIPTION
principal_id

Identifier of a user or group. 273948 is for all registered Synapse users and 273949 is for public access. None implies public access.

TYPE: int DEFAULT: None

access_type

Type of permission to be granted. One or more of CREATE, READ, DOWNLOAD, UPDATE, DELETE, CHANGE_PERMISSIONS.

Defaults to ['READ', 'DOWNLOAD']

TYPE: List[str] DEFAULT: None

modify_benefactor

Set as True when modifying a benefactor's ACL

TYPE: bool DEFAULT: False

warn_if_inherits

Set as False, when creating a new ACL. Trying to modify the ACL of an Entity that inherits its ACL will result in a warning

TYPE: bool DEFAULT: True

overwrite

By default this function overwrites existing permissions for the specified user. Set this flag to False to add new permissions non-destructively.

TYPE: bool DEFAULT: True

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.

TYPE: Optional[Synapse] DEFAULT: None

RETURNS DESCRIPTION
Dict[str, Union[str, list]]

An Access Control List object

Setting permissions

Grant all registered users download access

File(id="syn123").set_permissions(principal_id=273948, access_type=['READ','DOWNLOAD'])

Grant the public view access

File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
Source code in synapseclient/models/protocols/access_control_protocol.py
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
def set_permissions(
    self,
    principal_id: int = None,
    access_type: List[str] = None,
    modify_benefactor: bool = False,
    warn_if_inherits: bool = True,
    overwrite: bool = True,
    *,
    synapse_client: Optional[Synapse] = None,
) -> Dict[str, Union[str, list]]:
    """
    Sets permission that a user or group has on an Entity.
    An Entity may have its own ACL or inherit its ACL from a benefactor.

    Arguments:
        principal_id: Identifier of a user or group. `273948` is for all
            registered Synapse users and `273949` is for public access.
            None implies public access.
        access_type: Type of permission to be granted. One or more of CREATE,
            READ, DOWNLOAD, UPDATE, DELETE, CHANGE_PERMISSIONS.

            **Defaults to ['READ', 'DOWNLOAD']**
        modify_benefactor: Set as True when modifying a benefactor's ACL
        warn_if_inherits: Set as False, when creating a new ACL. Trying to modify
            the ACL of an Entity that inherits its ACL will result in a warning
        overwrite: By default this function overwrites existing permissions for
            the specified user. Set this flag to False to add new permissions
            non-destructively.
        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:
        An Access Control List object

    Example: Setting permissions
        Grant all registered users download access

            File(id="syn123").set_permissions(principal_id=273948, access_type=['READ','DOWNLOAD'])

        Grant the public view access

            File(id="syn123").set_permissions(principal_id=273949, access_type=['READ'])
    """
    return {}

synapseclient.models.file.FileHandle dataclass

A file handle is a pointer to a file stored in a specific location.

ATTRIBUTE DESCRIPTION
id

The ID of this FileHandle. All references to this FileHandle will use this ID. Synapse will generate this ID when the FileHandle is created.

TYPE: Optional[str]

etag

FileHandles are immutable from the perspective of the API. The only field that can be change is the previewId. When a new previewId is set, the etag will change.

TYPE: Optional[str]

created_by

The ID Of the user that created this file.

TYPE: Optional[str]

created_on

The date when this file was uploaded.

TYPE: Optional[str]

modified_on

The date when the file was modified. This is handled by the backend and cannot be modified.

TYPE: Optional[str]

concrete_type

This is used to indicate the implementation of this interface. For example, an S3FileHandle should be set to: org.sagebionetworks.repo.model.file.S3FileHandle

TYPE: Optional[str]

content_type

TYPE: Optional[str]

content_md5

The file's content MD5.

TYPE: Optional[str]

file_name

The short, user visible name for this file.

TYPE: Optional[str]

storage_location_id

The optional storage location descriptor.

TYPE: Optional[int]

content_size

The size of the file in bytes.

TYPE: Optional[int]

status

The status of the file handle as computed by the backend. This value cannot be changed, any file handle that is not AVAILABLE should not be used.

TYPE: Optional[str]

bucket_name

The name of the bucket where this file resides.

TYPE: Optional[str]

key

The path or resource name for this object.

TYPE: Optional[str]

preview_id

If this file has a preview, then this will be the file ID of the preview.

TYPE: Optional[str]

is_preview

Whether or not this is a preview of another file.

TYPE: Optional[bool]

external_url

The URL of the file if it is stored externally.

TYPE: Optional[str]

Source code in synapseclient/models/file.py
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
@dataclass()
class FileHandle:
    """A file handle is a pointer to a file stored in a specific location.

    Attributes:
        id: The ID of this FileHandle. All references to this FileHandle will use this
            ID. Synapse will generate this ID when the FileHandle is created.
        etag: FileHandles are immutable from the perspective of the API. The only field
            that can be change is the previewId. When a new previewId is set, the
            etag will change.
        created_by: The ID Of the user that created this file.
        created_on: The date when this file was uploaded.
        modified_on: The date when the file was modified. This is handled by the backend
            and cannot be modified.
        concrete_type: This is used to indicate the implementation of this interface.
            For example, an S3FileHandle should be set to:
            org.sagebionetworks.repo.model.file.S3FileHandle
        content_type: Must be: <http://en.wikipedia.org/wiki/Internet_media_type>.
        content_md5: The file's content MD5.
        file_name: The short, user visible name for this file.
        storage_location_id: The optional storage location descriptor.
        content_size: The size of the file in bytes.
        status: The status of the file handle as computed by the backend. This value
            cannot be changed, any file handle that is not AVAILABLE should not be used.
        bucket_name: The name of the bucket where this file resides.
        key: The path or resource name for this object.
        preview_id: If this file has a preview, then this will be the file ID of the
            preview.
        is_preview: Whether or not this is a preview of another file.
        external_url: The URL of the file if it is stored externally.
    """

    id: Optional[str] = None
    """The ID of this FileHandle. All references to this FileHandle will use this ID.
        Synapse will generate this ID when the FileHandle is created."""

    etag: Optional[str] = None
    """
    FileHandles are immutable from the perspective of the API. The only field that can
    be change is the previewId. When a new previewId is set, the etag will change.
    """

    created_by: Optional[str] = None
    """The ID Of the user that created this file."""

    created_on: Optional[str] = None
    """The date when this file was uploaded."""

    modified_on: Optional[str] = None
    """The date when the file was modified. This is handled by the backend and cannot
    be modified."""

    concrete_type: Optional[str] = None
    """
    This is used to indicate the implementation of this interface. For example,
    an S3FileHandle should be set to: org.sagebionetworks.repo.model.file.S3FileHandle
    """

    content_type: Optional[str] = None
    """Must be: <http://en.wikipedia.org/wiki/Internet_media_type>."""

    content_md5: Optional[str] = None
    """The file's content MD5."""

    file_name: Optional[str] = None
    """The short, user visible name for this file."""

    storage_location_id: Optional[int] = None
    """The optional storage location descriptor."""

    content_size: Optional[int] = None
    """The size of the file in bytes."""

    status: Optional[str] = None
    """The status of the file handle as computed by the backend. This value cannot be
    changed, any file handle that is not AVAILABLE should not be used."""

    bucket_name: Optional[str] = None
    """The name of the bucket where this file resides."""

    key: Optional[str] = None
    """The path or resource name for this object."""

    preview_id: Optional[str] = None
    """If this file has a preview, then this will be the file ID of the preview."""

    is_preview: Optional[bool] = None
    """Whether or not this is a preview of another file."""

    external_url: Optional[str] = None
    """The URL of the file if it is stored externally."""

    def fill_from_dict(
        self, synapse_instance: Dict[str, Union[bool, str, int]]
    ) -> "FileHandle":
        """
        Converts a response from the REST API into this dataclass.

        Arguments:
            synapse_instance: The response from the REST API.
            set_annotations: Whether to set the annotations from the response.

        Returns:
            The File object.
        """
        file_handle = self or FileHandle()
        file_handle.id = synapse_instance.get("id", None)
        file_handle.etag = synapse_instance.get("etag", None)
        file_handle.created_by = synapse_instance.get("createdBy", None)
        file_handle.created_on = synapse_instance.get("createdOn", None)
        file_handle.modified_on = synapse_instance.get("modifiedOn", None)
        file_handle.concrete_type = synapse_instance.get("concreteType", None)
        file_handle.content_type = synapse_instance.get("contentType", None)
        file_handle.content_md5 = synapse_instance.get("contentMd5", None)
        file_handle.file_name = synapse_instance.get("fileName", None)
        file_handle.storage_location_id = synapse_instance.get(
            "storageLocationId", None
        )
        file_handle.content_size = synapse_instance.get("contentSize", None)
        file_handle.status = synapse_instance.get("status", None)
        file_handle.bucket_name = synapse_instance.get("bucketName", None)
        file_handle.key = synapse_instance.get("key", None)
        file_handle.preview_id = synapse_instance.get("previewId", None)
        file_handle.is_preview = synapse_instance.get("isPreview", None)
        file_handle.external_url = synapse_instance.get("externalURL", None)

        return self

    def _convert_into_legacy_file_handle(self) -> Dict[str, Union[str, bool, int]]:
        """Convert the file handle object into a legacy File Handle object."""
        return_data = {
            "id": self.id,
            "etag": self.etag,
            "createdBy": self.created_by,
            "createdOn": self.created_on,
            "modifiedOn": self.modified_on,
            "concreteType": self.concrete_type,
            "contentType": self.content_type,
            "contentMd5": self.content_md5,
            "fileName": self.file_name,
            "storageLocationId": self.storage_location_id,
            "contentSize": self.content_size,
            "status": self.status,
            "bucketName": self.bucket_name,
            "key": self.key,
            "previewId": self.preview_id,
            "isPreview": self.is_preview,
            "externalURL": self.external_url,
        }
        delete_none_keys(return_data)
        return return_data