brynq-sdk-azure 1.0.1__tar.gz → 1.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/PKG-INFO +1 -1
- brynq_sdk_azure-1.1.1/brynq_sdk/azure/blob_storage.py +175 -0
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk_azure.egg-info/PKG-INFO +1 -1
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/setup.py +1 -1
- brynq_sdk_azure-1.0.1/brynq_sdk/azure/blob_storage.py +0 -95
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk/azure/__init__.py +0 -0
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk/azure/azure_connection.py +0 -0
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk/azure/entra.py +0 -0
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk_azure.egg-info/SOURCES.txt +0 -0
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk_azure.egg-info/dependency_links.txt +0 -0
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk_azure.egg-info/not-zip-safe +0 -0
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk_azure.egg-info/requires.txt +0 -0
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk_azure.egg-info/top_level.txt +0 -0
- {brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/setup.cfg +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from brynq_sdk.brynq import BrynQ
|
|
2
|
+
from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient, generate_account_sas, ResourceTypes, AccountSasPermissions
|
|
3
|
+
from typing import Union, List, Tuple
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BlobStorage(BrynQ):
|
|
8
|
+
def __init__(self, label: Union[str, List]):
|
|
9
|
+
super().__init__()
|
|
10
|
+
self.blob_service_client = self.__get_authentication(label=label)
|
|
11
|
+
|
|
12
|
+
def __get_authentication(self, label):
|
|
13
|
+
credentials = self.get_system_credential(system='azure-blob-storage', label=label)
|
|
14
|
+
storage_account_name = credentials['storage_account_name']
|
|
15
|
+
storage_account_key = credentials['storage_account_key']
|
|
16
|
+
sas_token = generate_account_sas(
|
|
17
|
+
account_name=storage_account_name,
|
|
18
|
+
account_key=storage_account_key,
|
|
19
|
+
resource_types=ResourceTypes(service=True, container=True, object=True),
|
|
20
|
+
permission=AccountSasPermissions(read=True, write=True, list=True, delete=True, add=True, create=True, update=True, process=True),
|
|
21
|
+
expiry=datetime.utcnow() + timedelta(hours=1)
|
|
22
|
+
)
|
|
23
|
+
blob_service_client = BlobServiceClient(
|
|
24
|
+
account_url=f"https://{storage_account_name}.blob.core.windows.net",
|
|
25
|
+
credential=sas_token
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
return blob_service_client
|
|
29
|
+
|
|
30
|
+
def get_containers(self):
|
|
31
|
+
all_containers = self.blob_service_client.list_containers(include_metadata=True)
|
|
32
|
+
container_list = []
|
|
33
|
+
for container in all_containers:
|
|
34
|
+
container_info = {
|
|
35
|
+
'name': container.name,
|
|
36
|
+
'last_modified': container.last_modified,
|
|
37
|
+
'etag': container.etag,
|
|
38
|
+
'lease_state': container.lease,
|
|
39
|
+
'has_immutability_policy': container.has_immutability_policy,
|
|
40
|
+
'has_legal_hold': container.has_legal_hold,
|
|
41
|
+
'metadata': container.metadata
|
|
42
|
+
}
|
|
43
|
+
container_list.append(container_info)
|
|
44
|
+
|
|
45
|
+
return container_list
|
|
46
|
+
|
|
47
|
+
def get_container(self, container_name: str):
|
|
48
|
+
"""
|
|
49
|
+
Get a container from the blob storage
|
|
50
|
+
"""
|
|
51
|
+
container = self.blob_service_client.get_container_client(container_name)
|
|
52
|
+
return container
|
|
53
|
+
|
|
54
|
+
def create_container(self, container_name: str):
|
|
55
|
+
"""
|
|
56
|
+
Create a container in the blob storage
|
|
57
|
+
"""
|
|
58
|
+
response = self.blob_service_client.create_container(container_name)
|
|
59
|
+
return response
|
|
60
|
+
|
|
61
|
+
def update_container(self):
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
def delete_container(self):
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
def get_folders(self, container_name: str):
|
|
68
|
+
"""
|
|
69
|
+
Retrieves a list of 'folders' in the specified container.
|
|
70
|
+
Since Azure Blob Storage uses a flat namespace, folders are simulated using prefixes.
|
|
71
|
+
|
|
72
|
+
:param container_name: The name of the container.
|
|
73
|
+
:return: A list of folder names.
|
|
74
|
+
"""
|
|
75
|
+
container_client = self.get_container(container_name)
|
|
76
|
+
blobs_list = container_client.list_blobs()
|
|
77
|
+
|
|
78
|
+
folder_set = set()
|
|
79
|
+
for blob in blobs_list:
|
|
80
|
+
if '/' in blob.name:
|
|
81
|
+
folder = blob.name.split('/')[0]
|
|
82
|
+
folder_set.add(folder)
|
|
83
|
+
folders = list(folder_set)
|
|
84
|
+
return folders
|
|
85
|
+
|
|
86
|
+
def create_folder(self, container_name: str, folder_name: str):
|
|
87
|
+
"""
|
|
88
|
+
Create a file with a 0 as content. Because the file is created, the folder is also created. After that the file and the folder are created,
|
|
89
|
+
delete the file so the folder will stay. According to the azure docs, it should be possible to create empty files, but this is not working.
|
|
90
|
+
"""
|
|
91
|
+
# Split the url and add the container and folder name in between the url
|
|
92
|
+
original_url = self.blob_service_client.url.split('?')
|
|
93
|
+
url = f"{original_url[0]}/{container_name}/{folder_name}/empty_file?{original_url[1]}"
|
|
94
|
+
blob = BlobClient.from_blob_url(blob_url=url)
|
|
95
|
+
|
|
96
|
+
# Now create the file and delete it so the folder will stay
|
|
97
|
+
response = blob.upload_blob(b"0", blob_type='AppendBlob')
|
|
98
|
+
blob.delete_blob()
|
|
99
|
+
return response
|
|
100
|
+
|
|
101
|
+
def delete_folder(self, container_name: str, folder_name: str):
|
|
102
|
+
"""
|
|
103
|
+
Deletes all the blobs (files) within a folder, effectively deleting the folder.
|
|
104
|
+
:param container_name: The name of the container.
|
|
105
|
+
:param folder_name: The name of the folder to delete.
|
|
106
|
+
"""
|
|
107
|
+
container_client = self.get_container(container_name)
|
|
108
|
+
blobs = container_client.list_blobs(name_starts_with=f"{folder_name}/")
|
|
109
|
+
for blob in blobs:
|
|
110
|
+
blob_client = container_client.get_blob_client(blob)
|
|
111
|
+
blob_client.delete_blob()
|
|
112
|
+
return f"Deleted folder {folder_name} and all its contents."
|
|
113
|
+
|
|
114
|
+
def get_files(self, container_name: str, folder_name: str = ""):
|
|
115
|
+
"""
|
|
116
|
+
Retrieves all files in a container, optionally filtered by folder.
|
|
117
|
+
:param container_name: The name of the container.
|
|
118
|
+
:param folder_name: The name of the folder (optional). If provided, only files in this folder will be listed.
|
|
119
|
+
:return: A list of file names in the container or folder.
|
|
120
|
+
"""
|
|
121
|
+
container_client = self.get_container(container_name)
|
|
122
|
+
blobs_list = container_client.list_blobs(name_starts_with=f"{folder_name}/" if folder_name else "")
|
|
123
|
+
|
|
124
|
+
file_list = []
|
|
125
|
+
for blob in blobs_list:
|
|
126
|
+
if not blob.name.endswith('/'): # Exclude folder markers
|
|
127
|
+
file_list.append(blob.name)
|
|
128
|
+
|
|
129
|
+
return file_list
|
|
130
|
+
|
|
131
|
+
def upload_file(self, container_name: str, blob_name: str, file_path: str, overwrite: bool = False):
|
|
132
|
+
"""
|
|
133
|
+
Uploads a single file to Azure Blob Storage.
|
|
134
|
+
:param container_name: The name of the container to upload to.
|
|
135
|
+
:param blob_name: The name of the blob (the file name in blob storage).
|
|
136
|
+
:param file_path: The local path to the file to upload.
|
|
137
|
+
:param overwrite: Whether to overwrite an existing blob. Default is False.
|
|
138
|
+
"""
|
|
139
|
+
# Get the container client
|
|
140
|
+
container_client = self.get_container(container_name)
|
|
141
|
+
|
|
142
|
+
# Get the blob client
|
|
143
|
+
blob_client = container_client.get_blob_client(blob_name)
|
|
144
|
+
|
|
145
|
+
# Open the file and upload
|
|
146
|
+
with open(file_path, "rb") as data:
|
|
147
|
+
blob_client.upload_blob(data, overwrite=overwrite)
|
|
148
|
+
|
|
149
|
+
print(f"Successfully uploaded {file_path} to {blob_client.url}")
|
|
150
|
+
return blob_client.url
|
|
151
|
+
|
|
152
|
+
def upload_files(self, container_name: str, files: List[Tuple[str, str]], overwrite: bool = False):
|
|
153
|
+
"""
|
|
154
|
+
Uploads multiple files to Azure Blob Storage.
|
|
155
|
+
:param container_name: The name of the container to upload to.
|
|
156
|
+
:param files: A list of tuples (blob_name, file_path), where blob_name is the name of the blob in storage, and file_path is the local file path.
|
|
157
|
+
:param overwrite: Whether to overwrite existing blobs. Default is False.
|
|
158
|
+
"""
|
|
159
|
+
success = True
|
|
160
|
+
for blob_name, file_path in files:
|
|
161
|
+
result = self.upload_file(container_name, blob_name, file_path, overwrite=overwrite)
|
|
162
|
+
if result is None:
|
|
163
|
+
success = False
|
|
164
|
+
return success
|
|
165
|
+
|
|
166
|
+
def delete_file(self, container_name: str, blob_name: str):
|
|
167
|
+
"""
|
|
168
|
+
Deletes a specific file from Azure Blob Storage.
|
|
169
|
+
:param container_name: The name of the container.
|
|
170
|
+
:param blob_name: The name of the blob (the file) to delete.
|
|
171
|
+
"""
|
|
172
|
+
container_client = self.get_container(container_name)
|
|
173
|
+
blob_client = container_client.get_blob_client(blob_name)
|
|
174
|
+
blob_client.delete_blob()
|
|
175
|
+
return f"Deleted file {blob_name} from container {container_name}."
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
from brynq_sdk.brynq import BrynQ
|
|
2
|
-
from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient, generate_account_sas, ResourceTypes, AccountSasPermissions
|
|
3
|
-
from typing import Union, List
|
|
4
|
-
from datetime import datetime, timedelta
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class BlobStorage(BrynQ):
|
|
8
|
-
def __init__(self, label: Union[str, List]):
|
|
9
|
-
super().__init__()
|
|
10
|
-
self.blob_service_client = self.__get_authentication(label=label)
|
|
11
|
-
|
|
12
|
-
def __get_authentication(self, label):
|
|
13
|
-
credentials = self.get_system_credential(system='azure-blob-storage', label=label)
|
|
14
|
-
storage_account_name = credentials['storage_account_name']
|
|
15
|
-
storage_account_key = credentials['storage_account_key']
|
|
16
|
-
sas_token = generate_account_sas(
|
|
17
|
-
account_name=storage_account_name,
|
|
18
|
-
account_key=storage_account_key,
|
|
19
|
-
resource_types=ResourceTypes(service=True, container=True, object=True),
|
|
20
|
-
permission=AccountSasPermissions(read=True, write=True, list=True, delete=True, add=True, create=True, update=True, process=True),
|
|
21
|
-
expiry=datetime.utcnow() + timedelta(hours=1)
|
|
22
|
-
)
|
|
23
|
-
blob_service_client = BlobServiceClient(
|
|
24
|
-
account_url=f"https://{storage_account_name}.blob.core.windows.net",
|
|
25
|
-
credential=sas_token
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
return blob_service_client
|
|
29
|
-
|
|
30
|
-
def get_containers(self):
|
|
31
|
-
all_containers = self.blob_service_client.list_containers(include_metadata=True)
|
|
32
|
-
container_list = []
|
|
33
|
-
for container in all_containers:
|
|
34
|
-
container_info = {
|
|
35
|
-
'name': container.name,
|
|
36
|
-
'last_modified': container.last_modified,
|
|
37
|
-
'etag': container.etag,
|
|
38
|
-
'lease_state': container.lease,
|
|
39
|
-
'has_immutability_policy': container.has_immutability_policy,
|
|
40
|
-
'has_legal_hold': container.has_legal_hold,
|
|
41
|
-
'metadata': container.metadata
|
|
42
|
-
}
|
|
43
|
-
container_list.append(container_info)
|
|
44
|
-
|
|
45
|
-
return container_list
|
|
46
|
-
|
|
47
|
-
def get_container(self, container_name: str):
|
|
48
|
-
"""
|
|
49
|
-
Get a container from the blob storage
|
|
50
|
-
"""
|
|
51
|
-
container = self.blob_service_client.get_container_client(container_name)
|
|
52
|
-
return container
|
|
53
|
-
|
|
54
|
-
def create_container(self, container_name: str):
|
|
55
|
-
"""
|
|
56
|
-
Create a container in the blob storage
|
|
57
|
-
"""
|
|
58
|
-
response = self.blob_service_client.create_container(container_name)
|
|
59
|
-
return response
|
|
60
|
-
|
|
61
|
-
def update_container(self):
|
|
62
|
-
pass
|
|
63
|
-
|
|
64
|
-
def delete_container(self):
|
|
65
|
-
pass
|
|
66
|
-
|
|
67
|
-
def get_blobs(self):
|
|
68
|
-
pass
|
|
69
|
-
|
|
70
|
-
def create_blob(self):
|
|
71
|
-
pass
|
|
72
|
-
|
|
73
|
-
def delete_blob(self):
|
|
74
|
-
pass
|
|
75
|
-
|
|
76
|
-
def get_folders(self):
|
|
77
|
-
pass
|
|
78
|
-
|
|
79
|
-
def create_folder(self, container_name: str, folder_name: str):
|
|
80
|
-
"""
|
|
81
|
-
Create a file with a 0 as content. Because the file is created, the folder is also created. After that the file and the folder are created,
|
|
82
|
-
delete the file so the folder will stay. According to the azure docs, it should be possible to create empty files, but this is not working.
|
|
83
|
-
"""
|
|
84
|
-
# Split the url and add the container and folder name in between the url
|
|
85
|
-
original_url = self.blob_service_client.url.split('?')
|
|
86
|
-
url = f"{original_url[0]}/{container_name}/{folder_name}/empty_file?{original_url[1]}"
|
|
87
|
-
blob = BlobClient.from_blob_url(blob_url=url)
|
|
88
|
-
|
|
89
|
-
# Now create the file and delete it so the folder will stay
|
|
90
|
-
response = blob.upload_blob(b"0", blob_type='AppendBlob')
|
|
91
|
-
blob.delete_blob()
|
|
92
|
-
return response
|
|
93
|
-
|
|
94
|
-
def delete_folder(self):
|
|
95
|
-
pass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{brynq_sdk_azure-1.0.1 → brynq_sdk_azure-1.1.1}/brynq_sdk_azure.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|