1010
1111import logging
1212
13- from typing import Optional , Tuple
13+ from typing import Optional , Tuple , Union
14+
15+ if False :
16+ from b2sdk .api import B2Api
1417
1518from .encryption .setting import EncryptionSetting , EncryptionSettingFactory
1619from .encryption .types import EncryptionMode
4851logger = logging .getLogger (__name__ )
4952
5053
51- class Bucket (metaclass = B2TraceMeta ):
52- """
53- Provide access to a bucket in B2: listing files, uploading and downloading.
54- """
54+ class ValueNotSet :
55+ """Sentry class for signifying no value for a property was supplied"""
56+ pass
5557
56- DEFAULT_CONTENT_TYPE = AUTO_CONTENT_TYPE
58+
59+ class BucketStructure (metaclass = B2TraceMeta ):
60+ """Structure holding all attributes of a bucket."""
61+
62+ id_ : Union [str , ValueNotSet ]
63+ account_id : Union [str , ValueNotSet ]
64+ name : Union [str , ValueNotSet ]
65+ type_ : Union [str , ValueNotSet ]
66+ bucket_info : Union [dict , ValueNotSet ]
67+ cors_rules : Union [dict , ValueNotSet ]
68+ lifecycle_rules : Union [dict , ValueNotSet ]
69+ revision : Union [int , ValueNotSet ]
70+ bucket_dict : Union [dict , ValueNotSet ]
71+ options_set : Union [set , ValueNotSet ]
72+ default_server_side_encryption : Union [EncryptionSetting , ValueNotSet ]
73+ default_retention : Union [BucketRetentionSetting , ValueNotSet ]
74+ is_file_lock_enabled : Union [Optional [bool ], ValueNotSet ]
75+ replication : Union [Optional [ReplicationConfiguration ], ValueNotSet ]
5776
5877 def __init__ (
5978 self ,
60- api ,
6179 id_ ,
6280 name = None ,
6381 type_ = None ,
@@ -73,9 +91,10 @@ def __init__(
7391 default_retention : BucketRetentionSetting = UNKNOWN_BUCKET_RETENTION ,
7492 is_file_lock_enabled : Optional [bool ] = None ,
7593 replication : Optional [ReplicationConfiguration ] = None ,
94+ * ,
95+ account_id ,
7696 ):
7797 """
78- :param b2sdk.v2.B2Api api: an API object
7998 :param str id_: a bucket id
8099 :param str name: a bucket name
81100 :param str type_: a bucket type
@@ -89,9 +108,10 @@ def __init__(
89108 :param b2sdk.v2.BucketRetentionSetting default_retention: default retention setting
90109 :param bool is_file_lock_enabled: whether file locking is enabled or not
91110 :param b2sdk.v2.ReplicationConfiguration replication: replication rules for the bucket
111+ :param str account_id: id of the account owning the bucket
92112 """
93- self .api = api
94113 self .id_ = id_
114+ self .account_id = account_id
95115 self .name = name
96116 self .type_ = type_
97117 self .bucket_info = bucket_info or {}
@@ -105,6 +125,45 @@ def __init__(
105125 self .is_file_lock_enabled = is_file_lock_enabled
106126 self .replication = replication
107127
128+ def __repr__ (self ):
129+ return '%s<%s,%s,%s>' % (type (self ).__name__ , self .id_ , self .name , self .type_ )
130+
131+
132+ class Bucket (BucketStructure ):
133+ """
134+ Provide access to a bucket in B2: listing files, uploading and downloading.
135+ """
136+
137+ api : 'B2Api'
138+ id_ : str
139+ account_id : str
140+ name : str
141+ type_ : str
142+ bucket_info : dict
143+ cors_rules : dict
144+ lifecycle_rules : dict
145+ revision : int
146+ bucket_dict : dict
147+ options_set : set
148+ default_server_side_encryption : EncryptionSetting
149+ default_retention : BucketRetentionSetting
150+ is_file_lock_enabled : Optional [bool ]
151+ replication : Optional [ReplicationConfiguration ]
152+
153+ DEFAULT_CONTENT_TYPE = AUTO_CONTENT_TYPE
154+
155+ def __init__ (
156+ self ,
157+ api ,
158+ * args ,
159+ ** kwargs ,
160+ ):
161+ """
162+ :param b2sdk.v2.B2Api api: an API object
163+ """
164+ self .api = api
165+ super ().__init__ (* args , account_id = self .api .account_info .get_account_id (), ** kwargs )
166+
108167 def get_fresh_state (self ) -> 'Bucket' :
109168 """
110169 Fetch all the information about this bucket and return a new bucket object.
@@ -960,9 +1019,6 @@ def as_dict(self):
9601019
9611020 return result
9621021
963- def __repr__ (self ):
964- return 'Bucket<%s,%s,%s>' % (self .id_ , self .name , self .type_ )
965-
9661022
9671023class BucketFactory :
9681024 """
@@ -981,6 +1037,123 @@ def from_api_response(cls, api, response):
9811037 """
9821038 return [cls .from_api_bucket_dict (api , bucket_dict ) for bucket_dict in response ['buckets' ]]
9831039
1040+ @classmethod
1041+ def bucket_structure_from_dict (cls , bucket_dict ) -> BucketStructure :
1042+ """
1043+ Turn a dictionary, like this:
1044+
1045+ .. code-block:: python
1046+
1047+ {
1048+ "bucketType": "allPrivate",
1049+ "accountId": "0991231",
1050+ "bucketId": "a4ba6a39d8b6b5fd561f0010",
1051+ "bucketName": "zsdfrtsazsdfafr",
1052+ "accountId": "4aa9865d6f00",
1053+ "bucketInfo": {},
1054+ "options": [],
1055+ "revision": 1,
1056+ "defaultServerSideEncryption": {
1057+ "isClientAuthorizedToRead" : true,
1058+ "value": {
1059+ "algorithm" : "AES256",
1060+ "mode" : "SSE-B2"
1061+ }
1062+ },
1063+ "fileLockConfiguration": {
1064+ "isClientAuthorizedToRead": true,
1065+ "value": {
1066+ "defaultRetention": {
1067+ "mode": null,
1068+ "period": null
1069+ },
1070+ "isFileLockEnabled": false
1071+ }
1072+ },
1073+ "replicationConfiguration": {
1074+ "clientIsAllowedToRead": true,
1075+ "value": {
1076+ "asReplicationSource": {
1077+ "replicationRules": [
1078+ {
1079+ "destinationBucketId": "c5f35d53a90a7ea284fb0719",
1080+ "fileNamePrefix": "",
1081+ "includeExistingFiles": True,
1082+ "isEnabled": true,
1083+ "priority": 1,
1084+ "replicationRuleName": "replication-us-west"
1085+ },
1086+ {
1087+ "destinationBucketId": "55f34d53a96a7ea284fb0719",
1088+ "fileNamePrefix": "",
1089+ "includeExistingFiles": True,
1090+ "isEnabled": true,
1091+ "priority": 2,
1092+ "replicationRuleName": "replication-us-west-2"
1093+ }
1094+ ],
1095+ "sourceApplicationKeyId": "10053d55ae26b790000000006"
1096+ },
1097+ "asReplicationDestination": {
1098+ "sourceToDestinationKeyMapping": {
1099+ "10053d55ae26b790000000045": "10053d55ae26b790000000004",
1100+ "10053d55ae26b790000000046": "10053d55ae26b790030000004"
1101+ }
1102+ }
1103+ }
1104+ }
1105+ }
1106+
1107+ into a BucketStructure object.
1108+
1109+ :param dict bucket_dict: a dictionary with bucket properties
1110+ :rtype: BucketStructure
1111+
1112+ """
1113+ type_ = bucket_dict .get ('bucketType' , ValueNotSet ())
1114+ bucket_name = bucket_dict .get ('bucketName' , ValueNotSet ())
1115+ bucket_id = bucket_dict .get ('bucketId' , ValueNotSet ())
1116+ bucket_info = bucket_dict .get ('bucketInfo' , ValueNotSet ())
1117+ cors_rules = bucket_dict .get ('corsRules' , ValueNotSet ())
1118+ lifecycle_rules = bucket_dict .get ('lifecycleRules' , ValueNotSet ())
1119+ revision = bucket_dict .get ('revision' , ValueNotSet ())
1120+ options = set (bucket_dict ['options' ]) if 'options' in bucket_dict else ValueNotSet ()
1121+ account_id = bucket_dict .get ('accountId' , ValueNotSet ())
1122+
1123+ default_server_side_encryption = (
1124+ EncryptionSettingFactory .from_bucket_dict (bucket_dict )
1125+ if EncryptionSettingFactory .TOP_LEVEL_KEY in bucket_dict else ValueNotSet ()
1126+ )
1127+ replication = (
1128+ ReplicationConfigurationFactory .from_bucket_dict (bucket_dict ).value
1129+ if ReplicationConfigurationFactory .TOP_LEVEL_KEY in bucket_dict else ValueNotSet ()
1130+ )
1131+
1132+ if FileLockConfiguration .TOP_LEVEL_KEY in bucket_dict :
1133+ file_lock_configuration = FileLockConfiguration .from_bucket_dict (bucket_dict )
1134+ default_retention = file_lock_configuration .default_retention
1135+ is_file_lock_enabled = file_lock_configuration .is_file_lock_enabled
1136+ else :
1137+ default_retention = ValueNotSet ()
1138+ is_file_lock_enabled = ValueNotSet ()
1139+
1140+ return BucketStructure (
1141+ bucket_id ,
1142+ bucket_name ,
1143+ type_ ,
1144+ bucket_info ,
1145+ cors_rules ,
1146+ lifecycle_rules ,
1147+ revision ,
1148+ bucket_dict ,
1149+ options ,
1150+ default_server_side_encryption ,
1151+ default_retention ,
1152+ is_file_lock_enabled ,
1153+ replication ,
1154+ account_id = account_id ,
1155+ )
1156+
9841157 @classmethod
9851158 def from_api_bucket_dict (cls , api , bucket_dict ):
9861159 """
0 commit comments