UncountablePythonSDK 0.0.86__py3-none-any.whl → 0.0.87__py3-none-any.whl

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.

Potentially problematic release.


This version of UncountablePythonSDK might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.86
3
+ Version: 0.0.87
4
4
  Summary: Uncountable SDK
5
5
  Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
6
6
  Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
@@ -37,6 +37,7 @@ Requires-Dist: flask==3.*
37
37
  Requires-Dist: simplejson==3.*
38
38
  Requires-Dist: grpcio==1.67.1
39
39
  Requires-Dist: protobuf>=4.21.1
40
+ Requires-Dist: azure-storage-blob==12.*
40
41
  Provides-Extra: test
41
42
  Requires-Dist: mypy==1.*; extra == "test"
42
43
  Requires-Dist: ruff==0.*; extra == "test"
@@ -33,11 +33,12 @@ pkgs/argument_parser/_is_namedtuple.py,sha256=Rjc1bKanIPPogl3qG5JPBxglG1TqWYOo1n
33
33
  pkgs/argument_parser/argument_parser.py,sha256=XjWQdcWanfaCGdLx7c_yQtqbZp7db-KAWzw8sTpXOsY,17713
34
34
  pkgs/argument_parser/case_convert.py,sha256=NuJLJUJRbyVb6_Slen4uqaStEHbcOS1d-hBBfDrrw-c,605
35
35
  pkgs/filesystem_utils/__init__.py,sha256=NSsQrUCoGISBCqCCyq6_583sYHTVEQeDjDO8hvZn3ag,1261
36
+ pkgs/filesystem_utils/_blob_session.py,sha256=CtoB7PIocuZo8vvFIS_Rc-YR6KwzFB0rHUVPKFEbRAI,4862
36
37
  pkgs/filesystem_utils/_gdrive_session.py,sha256=GJuZYJq1W4QQ_7OLvZIMK99FgRq8FxJHg6cMUx9prtA,11077
37
38
  pkgs/filesystem_utils/_local_session.py,sha256=xFEYhAvNqrOYqwt4jrEYOuYkjJn0zclZhTelW_Q1-rw,2325
38
39
  pkgs/filesystem_utils/_s3_session.py,sha256=_jLK5C-UElT5Sl5teM2pFR7fQe11NlhUd04EgwN9FRs,3962
39
40
  pkgs/filesystem_utils/_sftp_session.py,sha256=6zoF7YsEUp0GpyFb-BeIhUAWvbTK7IUjvPNJ1B0vEyI,4743
40
- pkgs/filesystem_utils/file_type_utils.py,sha256=Xd-mg35mAENUgNJVz5uK8nEfrUp-NQld_gnXFEq3K-8,1487
41
+ pkgs/filesystem_utils/file_type_utils.py,sha256=Au79J66Rh_Yyt_dXctsygPAg1Y4QRawqwRhbvnCpDIY,1933
41
42
  pkgs/filesystem_utils/filesystem_session.py,sha256=BQ2Go8Mu9-GcnaWh2Pm4x7ugLVsres6XrOQ8RoiEpcE,1045
42
43
  pkgs/serialization/__init__.py,sha256=LifasRW0a50A3qRFmo2bf3FQ6TXhZWOTz2-CVTgPjcQ,753
43
44
  pkgs/serialization/missing_sentry.py,sha256=aM_9KxbCk9dVvXvcOKgkIQBqFWvLhv8QlIUCiuFEXMo,806
@@ -286,7 +287,7 @@ uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr
286
287
  uncountable/types/api/triggers/run_trigger.py,sha256=-oZgPyn43xEKSCs81DVNzwaYMCdRJxbM9GY6fsqKwf4,1090
287
288
  uncountable/types/api/uploader/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
288
289
  uncountable/types/api/uploader/invoke_uploader.py,sha256=6mwVG136oLp9JcbB2I-kZnrcm3aeZzYZB-SFjEImY2o,1314
289
- UncountablePythonSDK-0.0.86.dist-info/METADATA,sha256=M-eS-Ah9j0F9pCNkwlJufJM7CCpGxzqWeo_Q-Dk6SkE,2024
290
- UncountablePythonSDK-0.0.86.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
291
- UncountablePythonSDK-0.0.86.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
292
- UncountablePythonSDK-0.0.86.dist-info/RECORD,,
290
+ UncountablePythonSDK-0.0.87.dist-info/METADATA,sha256=DIWpmh2PIjuruJvh55KC8Bu0uj7BmEYU83OvZWDpOQs,2064
291
+ UncountablePythonSDK-0.0.87.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
292
+ UncountablePythonSDK-0.0.87.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
293
+ UncountablePythonSDK-0.0.87.dist-info/RECORD,,
@@ -0,0 +1,137 @@
1
+ from io import BytesIO
2
+
3
+ from azure.storage.blob import BlobServiceClient, ContainerClient
4
+
5
+ from pkgs.filesystem_utils.file_type_utils import (
6
+ FileObjectData,
7
+ FileSystemBlobConfig,
8
+ FileSystemFileReference,
9
+ FileSystemObject,
10
+ FileTransfer,
11
+ IncompatibleFileReference,
12
+ )
13
+
14
+ from .filesystem_session import FileSystemSession
15
+
16
+
17
+ def _add_slash(prefix: str) -> str:
18
+ if len(prefix) > 0 and prefix[-1] != "/":
19
+ prefix = prefix + "/"
20
+ return prefix
21
+
22
+
23
+ class BlobSession(FileSystemSession):
24
+ config: FileSystemBlobConfig
25
+
26
+ def __init__(self, blob_config: FileSystemBlobConfig) -> None:
27
+ super().__init__()
28
+ self.config = blob_config
29
+
30
+ def start(self) -> None:
31
+ self.service_client: BlobServiceClient | None = BlobServiceClient(
32
+ self.config.account_url, credential=self.config.credential
33
+ )
34
+ self.container_client: ContainerClient | None = (
35
+ self.service_client.get_container_client(self.config.container)
36
+ )
37
+
38
+ def __enter__(self) -> "BlobSession":
39
+ self.start()
40
+ return self
41
+
42
+ def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> None:
43
+ self.service_client = None
44
+ self.container_client = None
45
+
46
+ def list_files(
47
+ self,
48
+ dir_path: FileSystemObject,
49
+ *,
50
+ recursive: bool = False,
51
+ valid_extensions: list[str] | None = None,
52
+ ) -> list[FileSystemObject]:
53
+ if not isinstance(dir_path, FileSystemFileReference):
54
+ raise IncompatibleFileReference()
55
+
56
+ assert self.service_client is not None and self.container_client is not None, (
57
+ "call to list_files on uninitialized blob session"
58
+ )
59
+
60
+ filesystem_file_references: list[FileSystemObject] = []
61
+ prefix = _add_slash(dir_path.filepath)
62
+ for blob in self.container_client.list_blobs(name_starts_with=prefix):
63
+ if not recursive and (
64
+ blob.name == prefix or "/" in blob.name[len(prefix) :]
65
+ ):
66
+ continue
67
+ if valid_extensions is None or any(
68
+ blob.name.endswith(valid_extension)
69
+ for valid_extension in valid_extensions
70
+ ):
71
+ filesystem_file_references.append(
72
+ FileSystemFileReference(
73
+ filepath=blob.name,
74
+ )
75
+ )
76
+
77
+ return filesystem_file_references
78
+
79
+ def download_files(
80
+ self,
81
+ filepaths: list[FileSystemObject],
82
+ ) -> list[FileObjectData]:
83
+ downloaded_files: list[FileObjectData] = []
84
+ assert self.service_client is not None and self.container_client is not None, (
85
+ "call to download_files on uninitialized blob session"
86
+ )
87
+
88
+ for file_object in filepaths:
89
+ if (
90
+ not isinstance(file_object, FileSystemFileReference)
91
+ or file_object.filename is None
92
+ ):
93
+ raise IncompatibleFileReference()
94
+
95
+ blob_client = self.container_client.get_blob_client(file_object.filepath)
96
+ download_stream = blob_client.download_blob()
97
+ file_data = download_stream.readall()
98
+ downloaded_files.append(
99
+ FileObjectData(
100
+ file_data=file_data,
101
+ file_IO=BytesIO(file_data),
102
+ filename=file_object.filename,
103
+ filepath=file_object.filepath,
104
+ )
105
+ )
106
+
107
+ return downloaded_files
108
+
109
+ def move_files(self, file_mappings: list[FileTransfer]) -> None:
110
+ assert self.service_client is not None and self.container_client is not None, (
111
+ "call to move_files on uninitialized blob session"
112
+ )
113
+
114
+ for src_file, dest_file in file_mappings:
115
+ if not isinstance(src_file, FileSystemFileReference) or not isinstance(
116
+ dest_file, FileSystemFileReference
117
+ ):
118
+ raise IncompatibleFileReference()
119
+
120
+ source_blob_client = self.container_client.get_blob_client(
121
+ src_file.filepath
122
+ )
123
+ dest_blob_client = self.container_client.get_blob_client(dest_file.filepath)
124
+
125
+ dest_blob_client.start_copy_from_url(source_blob_client.url)
126
+ source_blob_client.delete_blob()
127
+
128
+ def delete_files(self, filepaths: list[FileSystemObject]) -> None:
129
+ assert self.service_client is not None and self.container_client is not None, (
130
+ "call to delete_files on uninitialized blob session"
131
+ )
132
+ for file_object in filepaths:
133
+ if not isinstance(file_object, FileSystemFileReference):
134
+ raise IncompatibleFileReference()
135
+
136
+ blob_client = self.container_client.get_blob_client(file_object.filepath)
137
+ blob_client.delete_blob()
@@ -4,6 +4,12 @@ from io import BytesIO
4
4
  from typing import Optional, Union
5
5
 
6
6
  import paramiko
7
+ from azure.core.credentials import (
8
+ AzureNamedKeyCredential,
9
+ AzureSasCredential,
10
+ TokenCredential,
11
+ )
12
+ from azure.storage.blob import ContainerProperties
7
13
 
8
14
 
9
15
  @dataclass
@@ -69,3 +75,17 @@ class FileSystemS3Config:
69
75
  access_key_id: Optional[str]
70
76
  secret_access_key: Optional[str]
71
77
  session_token: Optional[str]
78
+
79
+
80
+ @dataclass(kw_only=True)
81
+ class FileSystemBlobConfig:
82
+ account_url: str
83
+ credential: (
84
+ str
85
+ | dict[str, str]
86
+ | AzureNamedKeyCredential
87
+ | AzureSasCredential
88
+ | TokenCredential
89
+ | None
90
+ )
91
+ container: ContainerProperties | str