data-sourcerer 0.5.0__py3-none-any.whl → 0.6.0__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.
- {data_sourcerer-0.5.0.dist-info → data_sourcerer-0.6.0.dist-info}/METADATA +5 -1
- {data_sourcerer-0.5.0.dist-info → data_sourcerer-0.6.0.dist-info}/RECORD +10 -10
- sourcerer/__init__.py +1 -1
- sourcerer/infrastructure/storage_provider/services/azure.py +25 -2
- sourcerer/presentation/screens/question/styles.tcss +1 -1
- sourcerer/presentation/utils.py +14 -1
- sourcerer/settings.py +2 -0
- {data_sourcerer-0.5.0.dist-info → data_sourcerer-0.6.0.dist-info}/WHEEL +0 -0
- {data_sourcerer-0.5.0.dist-info → data_sourcerer-0.6.0.dist-info}/entry_points.txt +0 -0
- {data_sourcerer-0.5.0.dist-info → data_sourcerer-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: data-sourcerer
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.6.0
|
4
4
|
Summary: Sourcerer is a terminal cloud storage navigator.
|
5
5
|
Author-email: Bohdana Kuzmenko <bohdana.kuzmenko.dev@gmail.com>
|
6
6
|
License: MIT
|
@@ -59,6 +59,10 @@ engineers to view and manage files across multiple cloud providers like
|
|
59
59
|
|
60
60
|
## 🪄 Installation
|
61
61
|
|
62
|
+
```bash
|
63
|
+
pipx install data-sourcerer
|
64
|
+
```
|
65
|
+
or
|
62
66
|
```bash
|
63
67
|
pip install data-sourcerer
|
64
68
|
```
|
@@ -1,5 +1,5 @@
|
|
1
|
-
sourcerer/__init__.py,sha256=
|
2
|
-
sourcerer/settings.py,sha256=
|
1
|
+
sourcerer/__init__.py,sha256=DkeIRjUGxqUW4miR6E03MLfzrclIIf-JdZOmHGmwGl8,636
|
2
|
+
sourcerer/settings.py,sha256=OodDZ3USibZEXg56OKmUAMRWu_5QQ3byFoso5G31_xk,1496
|
3
3
|
sourcerer/utils.py,sha256=l5AitLCh58TdYwhC-Z2wQVXvq1q37ObuXeqDYba4hRU,1361
|
4
4
|
sourcerer/domain/__init__.py,sha256=rV21d-dD-e0q4EQ2LfWDSDLlrUOjnHnWBtWPujoue0o,556
|
5
5
|
sourcerer/domain/access_credentials/__init__.py,sha256=pFAwnr74uy09e7kubYsuaqzkVPkTA66dwjKzpIGQkAY,217
|
@@ -52,14 +52,14 @@ sourcerer/infrastructure/storage_provider/__init__.py,sha256=GONjDCsTmd6f_fF3lzx
|
|
52
52
|
sourcerer/infrastructure/storage_provider/exceptions.py,sha256=acx3IIXD2yWlzLvD2asJBEpKEa6eJW31uKkzzr8MrR4,3336
|
53
53
|
sourcerer/infrastructure/storage_provider/registry.py,sha256=8dbRLOx1jLK_i18uuh_JnKvId9NJBECKg4nG9F_dFH4,2249
|
54
54
|
sourcerer/infrastructure/storage_provider/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
|
-
sourcerer/infrastructure/storage_provider/services/azure.py,sha256=
|
55
|
+
sourcerer/infrastructure/storage_provider/services/azure.py,sha256=wNmNE0xjXxewD0FN5_13QLckHsT4HVuKds9LaQa5GjI,10577
|
56
56
|
sourcerer/infrastructure/storage_provider/services/gcp.py,sha256=HyiGF-xfUYnykZOaAqqAFpuASsf0Plcp3kPjfvRZuXM,9058
|
57
57
|
sourcerer/infrastructure/storage_provider/services/s3.py,sha256=avRAtgZTobKnovfCG_lnW9xZOG77cnpDnZGazn85XHc,9239
|
58
58
|
sourcerer/presentation/__init__.py,sha256=kzOeaTpy9hm61MLl_nybdooRrawFUd1uEX4f3Y-84ZU,472
|
59
59
|
sourcerer/presentation/app.py,sha256=ROu3vSWzo6d8W30A9Zqi5zdLcVeHJsGLDJMLTKrthHE,1018
|
60
60
|
sourcerer/presentation/di_container.py,sha256=m05fzDTGI11BXDQy1xmNl8rPHZfS1Zo_QlPhAhIyOHQ,2737
|
61
61
|
sourcerer/presentation/settings.py,sha256=TcoDQWzekC4pYBKTVrUoXZK5s05or_F0KXmW04P6uEA,1256
|
62
|
-
sourcerer/presentation/utils.py,sha256=
|
62
|
+
sourcerer/presentation/utils.py,sha256=CjCbnKqMi1foxdGDcHIKAhIXrrSY0Ec3K_CIp5jfFPI,3495
|
63
63
|
sourcerer/presentation/screens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
64
64
|
sourcerer/presentation/screens/about/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
65
65
|
sourcerer/presentation/screens/about/main.py,sha256=7CnXMOYHCmEHjvnEbyHbrV-RUsw3g0OZiKdyiDp1h-w,2091
|
@@ -105,7 +105,7 @@ sourcerer/presentation/screens/provider_creds_registration/main.py,sha256=CkGFef
|
|
105
105
|
sourcerer/presentation/screens/provider_creds_registration/styles.tcss,sha256=gd1SNeRoHTYwNzdGxK-2aDqNPeY5b2wFWajtoNn5--Y,612
|
106
106
|
sourcerer/presentation/screens/question/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
107
107
|
sourcerer/presentation/screens/question/main.py,sha256=7ogFbKrqP9deBYfgq7Bs6NkiSdy3whEu51mW_--TCIY,980
|
108
|
-
sourcerer/presentation/screens/question/styles.tcss,sha256=
|
108
|
+
sourcerer/presentation/screens/question/styles.tcss,sha256=EXH9Cs9JT3l6-hfHlwbVfUxBC5BLKtemh7PW98pSO2g,397
|
109
109
|
sourcerer/presentation/screens/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
110
110
|
sourcerer/presentation/screens/settings/main.py,sha256=sjFEqGKKJ1bfb901Vz21HPx-BRfndtXLFQ_jeRat_Gg,2464
|
111
111
|
sourcerer/presentation/screens/settings/styles.tcss,sha256=116APkhBck6ktct-P_wqokrm80edrkeA2NnwLYVqFak,705
|
@@ -129,8 +129,8 @@ sourcerer/presentation/screens/storages_registration/main.py,sha256=xam1qrUgmh7k
|
|
129
129
|
sourcerer/presentation/screens/storages_registration/styles.tcss,sha256=Yd78pkiaaShb30r5s6qlYlLxyB62DJNeAQqs_gMcP6k,601
|
130
130
|
sourcerer/presentation/themes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
131
131
|
sourcerer/presentation/themes/github_dark.py,sha256=9E1mEOr701nU-ZDSKBccMl3GYchroCEsxEVelm5oI-E,497
|
132
|
-
data_sourcerer-0.
|
133
|
-
data_sourcerer-0.
|
134
|
-
data_sourcerer-0.
|
135
|
-
data_sourcerer-0.
|
136
|
-
data_sourcerer-0.
|
132
|
+
data_sourcerer-0.6.0.dist-info/METADATA,sha256=yIQTYxCr8914q6ofJBZ78v1LwLVYP2k84VCRh8bbUKw,2657
|
133
|
+
data_sourcerer-0.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
134
|
+
data_sourcerer-0.6.0.dist-info/entry_points.txt,sha256=CyD02GehPW6QuhR5oDY5tLLRHQ9qbPXe0v3aT1pK3N8,62
|
135
|
+
data_sourcerer-0.6.0.dist-info/licenses/LICENSE,sha256=HjZ7RAG3i6izxvitGfY4feHfvW5F8DPj5eF0YBSf2rI,1073
|
136
|
+
data_sourcerer-0.6.0.dist-info/RECORD,,
|
sourcerer/__init__.py
CHANGED
@@ -6,12 +6,14 @@ interface for various cloud storage providers.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
import os.path
|
9
|
+
import threading
|
9
10
|
from collections.abc import Callable
|
10
11
|
from pathlib import Path
|
11
12
|
from typing import Any
|
12
13
|
|
13
14
|
from azure.mgmt.storage import StorageManagementClient
|
14
15
|
from azure.storage.blob import BlobServiceClient
|
16
|
+
from cachetools import LRUCache
|
15
17
|
from platformdirs import user_downloads_dir
|
16
18
|
|
17
19
|
from sourcerer.domain.shared.entities import StorageProvider
|
@@ -37,6 +39,8 @@ from sourcerer.infrastructure.utils import generate_uuid, is_text_file
|
|
37
39
|
|
38
40
|
@storage_provider(StorageProvider.AzureStorage)
|
39
41
|
class AzureStorageProviderService(BaseStorageProviderService):
|
42
|
+
MAX_CACHE_SIZE = 10
|
43
|
+
|
40
44
|
def __init__(self, credentials: Any):
|
41
45
|
"""
|
42
46
|
Initialize the service with Azure credentials.
|
@@ -48,6 +52,12 @@ class AzureStorageProviderService(BaseStorageProviderService):
|
|
48
52
|
self.subscription_id = credentials.subscription_id
|
49
53
|
self.cloud_suffix = credentials.cloud_suffix
|
50
54
|
|
55
|
+
self._storage_management_client: StorageManagementClient | None = None
|
56
|
+
self._blob_service_clients_lock = threading.Lock()
|
57
|
+
self._blob_service_clients: LRUCache[str, BlobServiceClient] = LRUCache(
|
58
|
+
maxsize=self.MAX_CACHE_SIZE
|
59
|
+
)
|
60
|
+
|
51
61
|
def get_accounts_client(self) -> StorageManagementClient:
|
52
62
|
"""
|
53
63
|
Get the Azure accounts client.
|
@@ -55,7 +65,13 @@ class AzureStorageProviderService(BaseStorageProviderService):
|
|
55
65
|
Returns:
|
56
66
|
Any: Azure accounts client
|
57
67
|
"""
|
58
|
-
|
68
|
+
if self._storage_management_client:
|
69
|
+
return self._storage_management_client
|
70
|
+
|
71
|
+
self._storage_management_client = StorageManagementClient(
|
72
|
+
self.credentials, self.subscription_id
|
73
|
+
)
|
74
|
+
return self._storage_management_client
|
59
75
|
|
60
76
|
def get_containers_client(self, storage: str):
|
61
77
|
"""
|
@@ -69,12 +85,19 @@ class AzureStorageProviderService(BaseStorageProviderService):
|
|
69
85
|
BlobServiceClient: An instance of the BlobServiceClient, configured with the
|
70
86
|
account URL and credentials.
|
71
87
|
"""
|
88
|
+
with self._blob_service_clients_lock:
|
89
|
+
if (client := self._blob_service_clients.get(storage)) is not None:
|
90
|
+
return client
|
91
|
+
|
72
92
|
account_url = "https://{account}.{cloud_suffix}"
|
73
|
-
|
93
|
+
client = BlobServiceClient(
|
74
94
|
account_url.format(account=storage, cloud_suffix=self.cloud_suffix),
|
75
95
|
credential=self.credentials,
|
76
96
|
retry_connect=0,
|
77
97
|
)
|
98
|
+
with self._blob_service_clients_lock:
|
99
|
+
self._blob_service_clients[storage] = client
|
100
|
+
return client
|
78
101
|
|
79
102
|
def list_storages(self) -> list[Storage]:
|
80
103
|
"""
|
sourcerer/presentation/utils.py
CHANGED
@@ -4,7 +4,9 @@ Utility functions for the presentation layer.
|
|
4
4
|
This module provides helper functions for the presentation layer,
|
5
5
|
particularly for retrieving and initializing storage provider services.
|
6
6
|
"""
|
7
|
+
from threading import Lock
|
7
8
|
|
9
|
+
from cachetools import LRUCache
|
8
10
|
from dependency_injector.wiring import Provide
|
9
11
|
|
10
12
|
from sourcerer.domain.access_credentials.repositories import BaseCredentialsRepository
|
@@ -15,6 +17,10 @@ from sourcerer.infrastructure.access_credentials.registry import (
|
|
15
17
|
)
|
16
18
|
from sourcerer.infrastructure.storage_provider.registry import storage_provider_registry
|
17
19
|
from sourcerer.presentation.di_container import DiContainer
|
20
|
+
from sourcerer.settings import MAX_CREDENTIALS_CACHE_SIZE
|
21
|
+
|
22
|
+
_provider_service_cache: LRUCache = LRUCache(maxsize=MAX_CREDENTIALS_CACHE_SIZE)
|
23
|
+
_provider_service_cache_lock = Lock()
|
18
24
|
|
19
25
|
|
20
26
|
def get_provider_service_by_access_uuid(
|
@@ -60,6 +66,10 @@ def get_provider_service_by_access_credentials(
|
|
60
66
|
authenticated credentials.
|
61
67
|
"""
|
62
68
|
|
69
|
+
with _provider_service_cache_lock:
|
70
|
+
if credentials.uuid in _provider_service_cache:
|
71
|
+
return _provider_service_cache[credentials.uuid]
|
72
|
+
|
63
73
|
credentials_service = access_credential_method_registry.get_by_provider_and_name(
|
64
74
|
credentials.provider, credentials.credentials_type
|
65
75
|
)
|
@@ -79,4 +89,7 @@ def get_provider_service_by_access_credentials(
|
|
79
89
|
)
|
80
90
|
except CredentialsAuthError:
|
81
91
|
return None
|
82
|
-
|
92
|
+
service = provider_service_class(auth_credentials)
|
93
|
+
with _provider_service_cache_lock:
|
94
|
+
_provider_service_cache[credentials.uuid] = service
|
95
|
+
return service
|
sourcerer/settings.py
CHANGED
File without changes
|
File without changes
|
File without changes
|